<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Kristopher Micinski</title>
    <description>Kris Micinski&apos;s Website. Love the lambda.
</description>
    <link>/</link>
    <atom:link href="/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Fri, 26 Jun 2026 11:10:38 -0400</pubDate>
    <lastBuildDate>Fri, 26 Jun 2026 11:10:38 -0400</lastBuildDate>
    <generator>Jekyll v4.4.1</generator>
    
      <item>
        <title>The Thing We All Obviously Want</title>
        <description>&lt;figure class=&quot;post-figure&quot;&gt;
  &lt;img src=&quot;/assets/private-moon.png&quot; alt=&quot;A retro travel-poster illustration of a couple beside a vintage car gazing at a large moon over a desert landscape&quot; /&gt;
  &lt;figcaption&gt;Generated by AI&amp;mdash;notice the perspective.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;Over the past year, we have seen the rapid development of AI-assisted
programming to an astounding degree. Even five years ago,
fully-automated program synthesis of large-scale, production systems
would have seemed unthinkable. Today, this is not an ambition, it is a
reality, at least by some measure. To some computer scientists,
natural-language-driven program synthesis was the endgame. On the
other hand, the software I use day-to-day doesn’t seem to be getting
appreciably better overall. Systems are still broken, apps
unresponsive (even on well-resourced hardware), crashes are still
common, and interfaces are generally as clunky as before. Personally,
I believe we will eventually see many systems adapted by AI-assisted
refactoring tools; but I also recognize there are human barriers to
deploying those things at full thrust in the short (even medium) term.&lt;/p&gt;

&lt;p&gt;In any case, my position is that AI-assisted programming, giving us
real-time, on-demand generation of any app, is the thing that we all
obviously want. There are a few tensions with this reality: (a) it
seriously changes the value proposition of what “code” is in a
meaningful way, (b) there are externalities: wasted computation,
energy replicating junk, and (c) it challenges the role of humans
in the knowledge-generation process.&lt;/p&gt;

&lt;p&gt;Note: In the rest of this essay I will use the term “LLM(s).” In
general, when I say this, I mean a state-of-the-art integration of a
frontier model alongside relatively simple tools (e.g., Claude Code,
Codex, etc.). There is some nuance in building these tools, but given
that the innovation is the model, I will casually refer to the whole
agentic process as the “LLM.”&lt;/p&gt;

&lt;h1 id=&quot;program-synthesis-did-it-fail&quot;&gt;Program Synthesis: Did it Fail?&lt;/h1&gt;

&lt;p&gt;Traditional program synthesis (by which I generally mean, SMT-based,
search-based, or similar) leveraged a rigorous and formal enumeration
/ proof to produce a synthesized program–potentially with a
certificate of its correctness–driven via a rigorous
specification. Like many academic fields, the goal of program
synthesis was not only to effect fully-automated programming tools: it
was to advance the frontier of understanding in semantics,
verification, specification, etc. These were the challenging problems,
especially given that traditional search (on the CPU) was so slow.&lt;/p&gt;

&lt;p&gt;LLMs allow rigorous concepts to gracefully degrade by using text. The
underlying model has such a deep understanding of language that fuzzy,
hazily-posed descriptions often still give &lt;em&gt;some&lt;/em&gt; sensible
interpretation. The obvious issue is hallucination: when you push the
embedding space into some inconsistency, won’t it just generate junk?
And of course, this is absolutely an issue–but when the error rate is
low enough that it’s practically useful, many people will not care.&lt;/p&gt;

&lt;p&gt;My position is that LLM-guided software engineering was so wildly
successful not just because it nailed the &lt;em&gt;generation&lt;/em&gt; part, but also
because LLMs ended up practically solving the problem of
&lt;em&gt;specification&lt;/em&gt;. Humans are simply used to the failure modes of
underspecification: even from a young age we’re trained to expect
disappointment if we miscommunicate our expectations, and so having
the LLM fail doesn’t sting as badly as you might expect.&lt;/p&gt;

&lt;h1 id=&quot;granularly-evolving-formal-specs&quot;&gt;Granularly-Evolving Formal Specs&lt;/h1&gt;

&lt;p&gt;One potential issue I foresee with current-generation AI is that
they focus the process on a textual-only workflow. In
practice, smart humans do want to read something that looks
like code most of the time–the issue is that they want to be able to
focus their limited mental attention rather than sifting through
thousands of lines of code. Most anybody who ever worked on a large
codebase (that they did not write entirely themselves) never had more
than an LLM-level understanding of parts of the codebase
anyway. Instead, we embarked upon code understanding efforts whenever
we faced tricky bugs, needed to add new features, etc. We codified
this in our own mental model (memory, notes, etc.), but also
(sometimes) documentation, bug reports, etc. Hilariously, this is now
the kind of thing that the LLM loves to ingest.&lt;/p&gt;

&lt;p&gt;As we build software, we want to be able to start with a hazy
specification (probably in English, but maybe in a big document) and
be able to begin building an application. At key decision-making
points we want to be able to solicit input and, finally, be dropped
into an exploratory state where we may make our thoughts more
granularly precise. For many reasons, I still believe that this should
be formal, executable code, not English prose.&lt;/p&gt;

&lt;p&gt;The issue is that no single language is perfect. English is great for
laypeople: any arbitrarily complex topic can be compressed into an
arbitrarily-simple soundbite. Unfortunately, English is imprecise and
even lies to you via the embedding. On the other end of the spectrum,
we might have Lean in a loop with the LLM. The LLM is speaking Lean
and there is some amount of grammar- and semantics-constrained
generation occurring. The issue here is one of information overload:
Lean is fully-rigorous, but complex propositions and definitions take
serious mental bandwidth to unpack as a nonexpert. Sure, you can ask
the LLM to explain, but it is not easy if you do not have a background
with advanced topics. We need something in between.&lt;/p&gt;

&lt;p&gt;There is obviously a market for programming environments which enable
granularly-precise constraint-guided software development. Many people
will attempt this first with English integration layers on top of
preexisting languages (e.g., Lean, C++, etc.). I wonder, however, if
there is room for families of languages which are focused on
abstracting around granularly-more-correct specifications of behavior,
with the understanding that (e.g.,) the LLM (or maybe a human) is
filling in the gaps.&lt;/p&gt;

&lt;h1 id=&quot;searchable-visualized-reactive-knowledge-bases&quot;&gt;Searchable, Visualized, Reactive Knowledge Bases&lt;/h1&gt;

&lt;p&gt;Many people are now using LLMs to build knowledge bases. The baseline
is simple: loose collections of textual notes are spat out by the LLM
and digested by a human, who iteratively interacts with a tool (Claude
Code) to build the knowledge base. Text is very useful, but it is not
always the best way to visualize information–I expect we will see a
growing corpus of applications which leverage LLMs to integrate into
some higher-level, application-specific knowledge base. As an example,
consider CAD components: we will often want some semi-programmatic
control over the development of a scene (e.g., laying out an office),
but we probably want to reuse previously-designed components (e.g.,
cabinets with a countertop) with slight tweaks–we want to ensure that
crucial constraints are met (e.g., always ensuring a uniform toe kick)
while enabling the AI to adapt a previously-built model in our
knowledge base. At some point it might be helpful to break apart an
item, say “base cabinet” versus “floor cabinet.” I expect there will
be a demand for gradually evolving things from unstructured,
generative objects into symbolic, computed representations.&lt;/p&gt;

&lt;h1 id=&quot;self-evolving-software&quot;&gt;Self-Evolving Software&lt;/h1&gt;

&lt;p&gt;I believe self-evolving software is already possible, perhaps it is
already here. Self-evolving software is software which optimizes and
evolves itself over time to suit a user’s needs. Right now, we prompt
the LLM with directions to build the app we desire. However, we can
easily imagine a future where software is optimized and evolved on
demand. For example, we might imagine being able to give gentle
nudges: “I don’t quite like the theme of the app,” which is then taken
as an instruction to evolve the application in the
background–whenever a change is tested, we can respond with a thumbs
up / down (or some more nuanced feedback signal). Since humans are
already doing this in production, it seems
reasonable to assume that very quickly this process will be
abstracted, and humans will begin to codify the &lt;em&gt;ways&lt;/em&gt; in which
software is allowed to evolve.&lt;/p&gt;

&lt;p&gt;This is partially an issue of modularity–we want to be able to
modularly decompose our concerns so that we can make rigorous
precisely what concerns us while leaving the rest up to the
LLM. Still, we seem to lack a good way to rigorously express the
constraints guiding a software system while leaving other parts
opaque. The issue seems to be that implementation details often form
leaky abstractions in practice, and right now English is the common
denominator: once you go beyond English formally, its ambiguity starts
leaking in.&lt;/p&gt;

&lt;h1 id=&quot;generation-replication-and-libraries&quot;&gt;Generation, Replication, and Libraries&lt;/h1&gt;

&lt;p&gt;For a time, humans pressed tab and enter. They would look at the app,
observe the feature, give input–it was beautiful. Through
rose-colored glasses, one might say that the skilled engineer could
spend 2-5 hours reading the code’s structure and architecting it
correctly, while the agent did the boring, tedious work. Through a
cynic’s perspective, there’s absolutely no sense in generating code
that you aren’t at least reading. We reconcile the two perspectives by
recognizing that the boundary constitutes the “library.”&lt;/p&gt;

&lt;p&gt;Thought experiment: imagine a world where the right library always
exists. In this world, you would only ever have to write 10kloc apps;
everything beyond 10kloc is pushed into a library. Some systems are not
really like this, and they do just take a ton of code. But
practically, nearly everything you could learn about in a university
class could be written in 10kloc or less, relatively efficiently, with
the right libraries.&lt;/p&gt;

&lt;p&gt;We are close (if not already there) to this vision with modern LLMs,
but we are not there in an important way: every time you want the
library, you regenerate it. This is obviously extremely wasteful: how
many to-do list apps do we really need to waste our energy generating?
In our thought experiment world where all libraries exist, imagine you
had an oracle that told you the right libraries you needed: could you
use a much cheaper model?&lt;/p&gt;

&lt;p&gt;In a way, this is just semantic caching. There will always be queries
made to the LLM where it has seen something “pretty close” before. In
an ideal world, this would be cached and we could do only the
incremental work necessary to generate the new response, optimally
balancing replication, generation, bandwidth, etc. costs.&lt;/p&gt;

&lt;h1 id=&quot;security-trust-oss-etc&quot;&gt;Security, Trust, OSS, Etc.&lt;/h1&gt;

&lt;p&gt;What is the point of well-maintained, agreed-upon code? In a world
where generating code is cheap, there are both upsides and
downsides. The clearest upside is this: there are many components
(e.g., container libraries, layout engines, etc.) for which having
stable, predictable, repeatable behavior will generally be
desirable. While many of us might want our own custom business CRM
(hopefully out of documented components), we still want to use Chrome,
too. On the other hand, in an age where LLMs have surpassed humans in
exploit identification, running the same software as everyone else
leaves us open to potential vulnerabilities.&lt;/p&gt;

&lt;p&gt;Another concern is the waste of pervasive use of neural models when
symbolic models suffice. Due to the current subsidies of frontier AI,
we will inevitably see waste when LLMs are used as general-purpose
reasoners when more specific reasoners would have sufficed. To some
degree, this is just an engineering problem: “LLMs” are complex
agentic workflows which build tools on-demand when necessary, and it
seems natural to predict that they will do so when valuable. Maybe the
question is: what is the use of reusable, OSS components to an LLM?&lt;/p&gt;

&lt;h1 id=&quot;human-human-and-human-llm-teaming&quot;&gt;Human-Human and Human-LLM Teaming&lt;/h1&gt;

&lt;p&gt;We used to team up to work on software by having a shared artifact:
the codebase. When we got hired, we would read the codebase and step
through it in a debugger, we would write a test that forced us to read
an execution path. But now that LLMs can do it just as well as we
can–at least to the functional constraints (the AI uses tests for its
reward, so this is predicted)–it is leaving lots of the industry
questioning: why read the code?&lt;/p&gt;

&lt;p&gt;Unfortunately though, while individual contributors have moved on to
mostly using English text to actually write the code, development
teams still generally interact by simply pushing the code. Other
engineers then use their LLM to help them read and maintain the
code. The issue here seems obvious: the substrate is still code
tracked in Git; if I’m working with someone who’s also using an LLM, I
don’t really just want the code. On the other hand, I personally do
like code; I don’t really just want to read a big sequential dump of
English either. What I want is to be able to rapidly interact with
someone in a way that lets us focus on just as much of the formal
specification as we want, leaving the rest underspecified.&lt;/p&gt;

&lt;h2 id=&quot;ai-acknowledgement&quot;&gt;AI Acknowledgement&lt;/h2&gt;

&lt;p&gt;I did &lt;em&gt;not&lt;/em&gt; use AI to write this post. However, I did use Claude for
two things: (a) I performed spellchecking, and (b) checks for
copyediting / consistency / etc.&lt;/p&gt;
</description>
        <pubDate>Fri, 26 Jun 2026 00:00:00 -0400</pubDate>
        <link>/thing-we-all-want</link>
        <guid isPermaLink="true">/thing-we-all-want</guid>
        
        
        <category>ai,</category>
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>My Rejected NSF CAREER Proposal</title>
        <description>&lt;p&gt;My NSF CAREER proposal was rejected, and I’m making it publicly
available: &lt;a href=&quot;/assets/Micinski_CAREER-rejected.pdf&quot;&gt;Micinski CAREER Proposal
(PDF)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The proposals scores were VG/G, VG/G, and E/VG. While the proposal was
rejected as competitive, my position is that the proposal is nicely
written and addresses a serious and important challenge in a credible
way. I also notice that the only PIs who have had NSF CAREER proposals
funded this year have been in AI / quantum–this is seriously
frustrating to see, given that NSF is a crucial research vehicle for
the US, and I am quite concerned that NSF is becoming a shell of its
former self, having been seriously damaged by &lt;a href=&quot;https://www.science.org/content/article/nsf-officials-break-silence-how-ai-and-quantum-now-drive-agency-grantmaking&quot;&gt;top-down
control&lt;/a&gt;. I
still strongly support NSF and will gladly review for it in the
future. Given that it is my last chance for the NSF CAREER before
tenure, I want to upload it for posterity. To all junior faculty
applying to NSF CAREER: best wishes, please feel free to reach out and
I am absolutely happy to send the full (unedited) reviews, I elide
them here to respect the reviewing process.&lt;/p&gt;

&lt;p&gt;While I’m frustrated at the rejection, my feeling is that (a) it was
somewhat my fault for not applying earlier (it’s well known that
second-attempt applicants often fail) and (b) the proposal was “not
AI/quantum enough.” I leave the entire thing here for you to read for
yourself, so you can be the judge.&lt;/p&gt;

&lt;p&gt;NSF is truly one of the most valuable institutions in the history of
the USA and the world generally, long live NSF!&lt;/p&gt;

&lt;p&gt;– Kristoper Micinski&lt;/p&gt;

</description>
        <pubDate>Thu, 09 Apr 2026 00:00:00 -0400</pubDate>
        <link>/rejected-career-proposal</link>
        <guid isPermaLink="true">/rejected-career-proposal</guid>
        
        
        <category>academia</category>
        
      </item>
    
      <item>
        <title>Why Study CS? Thoughts on LLM-assisted software engineering</title>
        <description>&lt;p&gt;Dear students of Computer Science,&lt;/p&gt;

&lt;p&gt;Almost everything everyone is telling you about LLMs is probably
wrong. Some tell you it’s glorified autocomplete, others say it will
cure cancer or prove the loftiest theorems. As with many mass-market
takes, these claims contain a grain of truth–but they miss the
point. I encourage you to try a modern AI coding assistant for
yourself and form your own opinion; here, I’ll offer mine, as someone
who wants to give you an optimistic but unvarnished perspective.&lt;/p&gt;

&lt;p&gt;Nine months ago (March ‘25), Anthropic’s CEO claimed that AI
assistants would be writing 90% of our code within three to six
months. We have recently seen that he was only a little too ambitious:
the winter break has seen an explosion of programmers uncovering the
power of Claude Code, surely a cause for talk around the Kombucha
dispenser at OpenAI’s offices.&lt;/p&gt;

&lt;p&gt;Claude Code reveals a sobering reality for many software engineering
professionals: the vast bulk of the thing we call productivity has now
revealed itself to be nothing more than Claude in a loop with
command-line tools. The 2023-era copy-and-pasting into the textbox,
manually crafting a prompt, and carefully stitching the result into
our codebase feels downright manual by comparison. Now, we can boot up
Claude Code and iteratively build up ideas, tests, implementations,
and (possibly) a complete, working app. The TUI-based interfaces solve
one of the main problems inherent to the web-based chatbots: how to
meaningfully &lt;em&gt;iterate&lt;/em&gt;, and incrementally build larger software
artifacts alongside the LLM. I think many of us were telling ourselves
that the real ingenuity was in the judiciousness we exercised when
carefully copying the LLM’s output and integrating it back into our
work: Claude Code shows that doing that for arbitrarily complex
domains is often just dirt simple, as long as the tools can
communicate via text.&lt;/p&gt;

&lt;p&gt;This halcyon turn of events has left many students wondering: should I
still study computer science? As someone who sells computer science
for a living, I am obligated to sell the position of “yes,” but we all
know that there are plenty of good reasons to argue “no” as well. For
the sake of this essay, I will assume you lean towards yes, but
perhaps with some skepticism. Even if you agree, it’s an important
question, because it reveals an uncomfortable systemic issue: many
students operate at a level that Claude Code can easily beat, and in
the new world order, it will be increasingly hard to get a job. Just
so we’re crystal clear, there’s still some code Claude can’t write,
even though it can certainly write a &lt;em&gt;lot&lt;/em&gt; of very useful code. But
“there will always be code that Claude can’t write” is not a very
convincing argument when the amount of code Claude does write will be
massively higher by comparison.&lt;/p&gt;

&lt;p&gt;CS undergraduates face a real issue: beating Claude Code isn’t very
easy, even (and especially) on challenging leetcode problems. This may
push some students to conclude that the AI is good enough at reasoning
such as to absolve them from developing a deep understanding of the
technical details. I argue that this is the wrong perspective to take,
and that instead you should switch your efforts away from mindless and
repetitive generation, and towards problems which stretch your
intellectual capacity by making you feel stuck. To the degree the LLM
can help get you unstuck in a way which genuinely builds your mental
model (so that &lt;em&gt;you’re&lt;/em&gt; in the driver’s seat, not a maybe-true
understanding you got from the AI): great, do it.&lt;/p&gt;

&lt;p&gt;In some ways, I see LLM-assisted software engineering as the Object
Orientation of the ’20s: it offers a vast swath of opportunity to give
lesser-trained programmers the ability to write huge amounts of
good-enough code, thus enabling us to hire a vast army of folks who
never had to deal with the pains of memory management, pointers,
etc. Unfortunately, however, this time it’s different; we all know the
hiring boom of easy-money days is over. Seeing Claude Code, many of us
take a more pessimistic stance: those that can’t add value on top of
Claude will be out of a job. Who are these folks that will rise to the
top? I argue that it is the people who have expended serious
intellectual energy to exercise their capacity for understanding deep
ideas.&lt;/p&gt;

&lt;p&gt;I personally believe the purpose of a university class is to stress
your intellectual capacity through repeated exposure to
increasingly-complex technical ideas which build coherent vision. In
doing this, we teach students skills that can be broadly binned into
generation (synthesis) and verification (checking). In many contexts
(e.g., debugging), we build our mental models via iterating between
synthesizing candidate ideas, then carefully checking our work, and
reflecting upon what to do next.&lt;/p&gt;

&lt;p&gt;As a student, I saw learning as a way of “compiling” things into my
mental representation: I would spend days at the library (I do not do
this anymore, my productivity has unfortunately declined) carefully
rewriting books in my own words, which taught me the difference
between what it meant to deeply grok something, and to possess an
LLM-level understanding of it. One thing I remember from those times,
however, is how mentally exhausted I felt at the end of the day. The
reason I was exhausted is because I was playing the verifier. I
learned a hard truth: after reading a sentence of a book, things often
make perfect sense, but when you try to explain it to someone else,
you realize you have no clue what is going on. When we do it to
ourselves we just feel stupid, but if it happens in an environment
that encourages rapid failure, we can grow: effective instructors
incentivize rapid failure (e.g., by allowing students to rapidly test
their solutions against an autograder).&lt;/p&gt;

&lt;p&gt;However, in the case of an LLM, failures often manifest in ways which
can be confusing and subtle: students may find themselves frustrated
to realize that the LLM led them into a hallucination. Feeling
confused about what to believe can be a very jarring
experience–leading many of us to feelings of repulsion when we read
some of our old code–but the LLM can further amplify this anxiety;
because it is &lt;em&gt;so&lt;/em&gt; shockingly capable of solving a problem, we feel
utterly paranoid about hearing the music stop, “what will I do if I
actually have to figure this part of the code out for myself?”&lt;/p&gt;

&lt;p&gt;One crucial skill software engineering students learn is how
to employ abstraction when they understand a software system: being
able to read &lt;em&gt;just enough&lt;/em&gt; of the whole system to understand its
architecture, and then employing iterative deepening to learn about
subsystems (e.g., the memory manager, networking, etc.) in an
on-demand fashion. Right now, many students are telling themselves a
comfortable lie: that iteratively prompting the LLM is a substitute
for the true iterative understanding we do to build our mental
model. Confirmation bias is a big concern: the tools are often so
good, they give us the impression that there is essentially no point
in checking their correctness most of the time. This sounds great,
until we get stuck, and then realize we actually didn’t understand
things nearly as well as necessary to tackle the task at hand.&lt;/p&gt;

&lt;p&gt;This is not a new problem, in fact it is the problem that has plagued
CS undergraduates since the beginning of time. Being stuck is
obviously deeply uncomfortable, because the real world has deadlines,
value-measuring systems, all of which depend on our work being
complete and correct in a timely fashion. No student wants to be
stuck, so they work to exit the stuck state as quickly as possible,
often latching on to an incorrect hypothesis (“oh wait, this line must
be broken…”) to get back to harmony; this is &lt;em&gt;bad&lt;/em&gt;. As you become a
senior software developer, you learn that being stuck is in fact the
&lt;em&gt;default&lt;/em&gt; state when you are working on challenging problems. The
mental energy comprising your engagement with courses should &lt;em&gt;not&lt;/em&gt; be
primarily bottlenecked by generation, instead, it should meaningfully
harmonize generation and verification in a way that allows you to
build an ever-expanding mental model.&lt;/p&gt;

&lt;p&gt;I recall years ago I chatted with a teaching professor about a
worrying trend in CS. This was around 2016, and they mentioned that
students were increasingly ignoring the “nuts and bolts” of
applications to focus only on the flashy bits that were easy to get
not-wrong. The specific concern was hackathons: do they encourage
students to do something hard and deep that exercises real engineering
skill? Or do they incentivize students to focus on startup-pitch-style
motivation with impressive-looking web interfaces backed by fake data?
The trend of students avoiding the genuinely-hard parts of the problem
to focus on the flashy parts has been occurring since long before the
days of AI coding assistants.&lt;/p&gt;

&lt;p&gt;Another professor recently told me that they switched their assessment
style to “code comprehension” rather than code synthesis. I think this
is an excellent way to see the problem, because it stresses that–when
generation is cheap–explanation, reconstructing a reason for
generated content, becomes the dominating factor in terms of assessing
understanding. You might ask: in a world where generators are perfect,
what is the role of the verifiers? This is an apt question.&lt;/p&gt;

&lt;p&gt;The first answer is that English is genuinely fuzzy, and in almost
every case, the ways in which humans describe specifications lead to
contradictory, unrealizable, or intractable results. In a world run by
humans, software engineers expend serious effort interfacing with
other humans to refine fuzzy conceptual architectures into correct
production software. While it seems reasonable to expect that Claude
Code could refine an English specification, there is always an
intrinsic value to working with another human. The issue with
automation is that this may no longer be worth the price: there &lt;em&gt;is&lt;/em&gt;
still a market for freelance web developers, for example, but it’s
been severely diminished by sites like SquareSpace and WordPress.&lt;/p&gt;

&lt;p&gt;LLMs take English-based automated code synthesis to the next level,
giving us a general-purpose tool to refine hazy specs into
mostly-working software. I predict different impacts across
sectors. Startups will be the most impacted: it has never been easier
to iterate to “something that looks like a passable minimum-viable
product.” If the goal is to demonstrate a cool market gap that is
tantamount to a JavaScript app, you can now do that &lt;em&gt;very&lt;/em&gt; quickly
with AI coding assistants. Enterprise apps, on the other hand, will
persist: organizational bloat, vendor lock-in, and sales play a huge
role in the momentum of those settings.&lt;/p&gt;

&lt;p&gt;The truly useful applications of AI will involve deeply leveraging AI
in a way that allows it to be built into the kinds of symbolic
workflows humans love in things like Keynote and Premiere Pro. For
example, Adobe Photoshop’s “generative fill” produces cool raster
images right now, but it doesn’t do so in a manner that gives you a
layered, element-by-element breakdown: this is the thing all of us
obviously actually want, because it lets us refine the results of the
AI, and interact with it, just like Claude Code did for our repos.&lt;/p&gt;

&lt;p&gt;Thus, to aspiring computer scientists, I urge you to seriously
consider how AI will impact your career. But I also urge you to
seriously resist the temptation to resort to mindlessly iterating with
the AI, toiling in unchecked guesses because you never bothered to go
check the notes or read the book. Of course such students existed
before LLMs as well: upon facing broken code, we &lt;em&gt;all&lt;/em&gt; have the
temptation to prove it is just a minor typo, we edit the code
superficially: sometimes it works, but sometimes it leads us to a
significantly more subtle error.&lt;/p&gt;

&lt;p&gt;There is a vast amount of potential in leveraging AI to expand our
intellectual capacity, by pushing us to rapidly confront our
misunderstandings and push past them. However, we often overestimate
the impact of change on the fundamental nature of things. At least in
your case, a CS student, your goal is to rise above regurgitation,
mimicry, or rearranging: we all know the parable of the junior
engineer who spent all their time trying to rearrange bits and pieces
of StackOverflow answers. The goal is thus, as it has always been, to
take from our time what we may use to most-optimally execute our
vision. In your time as a student, your objective is to learn the key
principles of computer science (or whatever field you choose) in a way
which maximally stresses your intellectual capacity while offering you
the ability to grow from repeated failure. Throughout your career, I
urge you to develop a taste for a specific set of topics in your
courses (or computing as a whole) for which you possess enough genuine
intellectual curiosity necessary to grok the true essence of things.&lt;/p&gt;

&lt;p&gt;– Kristopher Micinski, Syracuse&lt;/p&gt;

&lt;p&gt;P.s., a few caveats to this post: (a) like everyone else, I am being
reductive, there are plenty of domains where Claude Code completely
fails right now–paren matching in Racket is only one example. (b) I’m
specifically discussing Claude Code due to the recent explosion, but
the ideas were pioneered in other tools, and (c) there will surely be
plenty of reasonable folks who believe that AI is of &lt;em&gt;no&lt;/em&gt; (or very
limited) use to them, it is impossible for me to prove that all of
these people are wrong since utility depends on workload; I personally
found AI to be surprisingly helpful in my hobbyist woodworking,
however.&lt;/p&gt;
</description>
        <pubDate>Tue, 06 Jan 2026 00:00:00 -0500</pubDate>
        <link>/claude-code-and-why-study-cs</link>
        <guid isPermaLink="true">/claude-code-and-why-study-cs</guid>
        
        
        <category>ai</category>
        
      </item>
    
      <item>
        <title>Build a Compiler in Five Projects</title>
        <description>&lt;p&gt;Class website here: &lt;a href=&quot;https://kmicinski.com/cis531-f25&quot;&gt;https://kmicinski.com/cis531-f25&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Are you interested in building a compiler? Learning how functional
languages are implemented? Gaining a bit of practical experience with
x86-64 assembly language? If so, I invite you to try your hand at the
projects in my class,
&lt;a href=&quot;https://kmicinski.com/cis531-f25&quot;&gt;CIS531&lt;/a&gt;. CIS531 is a masters-level
class on compiler design which assumes that (a) you know how to
program, (b) you’ve had some exposure to C (know about stack
allocation, malloc, etc.), and (c) have seen some assembly code. My
class projects are in the Racket programming language, but if you
don’t know Racket, it is quite easy to learn: I have a &lt;a href=&quot;https://www.youtube.com/watch?v=2jrwXpUZW7k&amp;amp;list=PLXaqTeMx01E_eK1ZEpKvKL5KwSaj7cJW9&quot;&gt;set of YouTube
video lectures that teach Racket
quickly&lt;/a&gt;!
If you’ve never heard of Racket before, or you’re skeptical of
functional programming, indulge me for a bit: there’s no hardcore FP
theory or math in this course, and Racket is genuinely the best
language to use for this specific setup.&lt;/p&gt;

&lt;p&gt;My class follows Prof. Jeremy Siek’s excellent book, “Essentials of
Compilation.” While I highly recommend buying the book and supporting
Prof. Siek, I will also note that there are &lt;a href=&quot;https://brinckerhoff.org/clements/2194-csc431/essentials-of-compilation.pdf&quot;&gt;free online preliminary
editions&lt;/a&gt;
floating around; in my class, I followed the free version and
suggested that students buy the book if doing so fit their
goals. However, along with the book, I also have a set of class slides
along with sporadic course videos, both available on the &lt;a href=&quot;https://kmicinski.com/cis531-f25&quot;&gt;class
website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This class builds up to a compiler with the following features:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Variables and assignment via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;let&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Integer arithmetic via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Reading inputs / printing output&lt;/li&gt;
  &lt;li&gt;Booleans, conjunctions/disjunctions (and/or)&lt;/li&gt;
  &lt;li&gt;Branching via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt;, integer comparisons (&amp;lt;, etc.)&lt;/li&gt;
  &lt;li&gt;Heap-allocated vectors&lt;/li&gt;
  &lt;li&gt;Assignment / mutation (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set!&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;While loops&lt;/li&gt;
  &lt;li&gt;Fixed-arity functions and function application&lt;/li&gt;
  &lt;li&gt;Lambdas (closures at runtime)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The unique combination of features lets us tour an interesting
cross-section of programming languages, exploring both imperative
programming with loops and mutation but also functional programming
with lists and recursion.&lt;/p&gt;

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

&lt;p&gt;To be specific, I challenge you to complete five projects, each
including a comprehensive test suite that will seriously stress the
correctness of your implementation. p1 is a warmup project (you should
skip if you already know Racket), but p2-5 build a compiler for a set
of increasingly-complex languages to x86-64. The languages nest inside
of each other, with p2 giving us straight-line arithmetic, p3 giving
us decision trees, p4 giving us loops and mutation, and p5 giving us
functions, recursion, and lambdas.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://kmicinski.com/cis531-f25/projects/1&quot;&gt;p1 – Stack interpreter&lt;/a&gt;. This is
a warmup project, if you know Racket and have some PL background,
feel free to skip.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://kmicinski.com/cis531-f25/projects/2&quot;&gt;p2 – Straight-line arithmetic / variables → x86-64 assembly language&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://kmicinski.com/cis531-f25/projects/3&quot;&gt;p3 – Booleans and branching (if, and, or) → x86-64 assembly language&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://kmicinski.com/cis531-f25/projects/4&quot;&gt;p4 – Vectors, heap allocation, set!, and loops → x86-64 assembly language&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://kmicinski.com/cis531-f25/projects/5&quot;&gt;p5 – Functions, lambdas, and closure conversion → x86-64 assembly language&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The projects are designed with one key principle in mind: get us to
the &lt;em&gt;most expressive/fun language possible, as fast as possible&lt;/em&gt;. In
doing this, we sacrifice a lot that might be typically covered:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Our languages aren’t type/memory safe, we assume the programmer is
correct&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;No register allocation (possible to add, not too hard)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;No garbage collection of any kind: we &lt;em&gt;just use malloc&lt;/em&gt;. We could
trivially support the Boehm GC (I have done that in the past), but
it was another static library to link in and I really wanted to make
this self contained.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We support a &lt;em&gt;very&lt;/em&gt; limited set of builtins (but it is trivial to
add more)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So even after project 5, getting to a “real” compiler would take a bit
of effort. The most important (in my opinion) are (a) memory safety
(the language needs to be safe, period) via dynamic type tagging and
(b) slightly more builtins, and (c) register allocation. That would
get us to a respectable compiler. After that, we could add more
language features, or optimize the ones we have, e.g., by using
abstract interpretation.&lt;/p&gt;

&lt;h3 id=&quot;an-example-program&quot;&gt;An Example Program&lt;/h3&gt;

&lt;p&gt;Our language will include functions, loops, branching, assignment, and
even heap-allocated vectors. As an example of the power, here’s a
Sudoku solver written in the language&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(program
 ;; =========================
 ;; List primitives
 ;; Empty list is (void)
 ;; =========================
 (define (is_nil x) (eq? x (void)))

 ;; cons cell as 2-element vector: [0] = head, [1] = tail
 (define (cons h t)
   (let ([c (make-vector 2)])
     (let ([_ (vector-set! c 0 h)])
       (let ([_ (vector-set! c 1 t)])
         c))))

 (define (head c) (vector-ref c 0))
 (define (tail c) (vector-ref c 1))

 ;; =========================
 ;; Cell representation
 ;; cell = (row col val) as nested cons
 ;; =========================
 (define (make_cell r c v)
   (cons r (cons c (cons v (void)))))

 (define (cell_row cell)
   (head cell))

 (define (cell_col cell)
   (head (tail cell)))

 (define (cell_val cell)
   (head (tail (tail cell))))

 ;; =========================
 ;; Block indexing (0,1,2) for rows/cols
 ;; =========================
 (define (block_index3 x)
   (if (&amp;lt; x 3)
       0
       (if (&amp;lt; x 6)
           1
           2)))

 (define (same_block? r1 c1 r2 c2)
   (if (eq? (block_index3 r1) (block_index3 r2))
       (eq? (block_index3 c1) (block_index3 c2))
       #f))

 ;; =========================
 ;; Lookup current value at (row, col) in board
 ;; board is a list of cells
 ;; Return 0 if not assigned
 ;; =========================
 (define (lookup board row col)
   (if (is_nil board)
       0
       (let ([cell (head board)])
         (let ([r (cell_row cell)])
           (let ([c (cell_col cell)])
             (if (and (eq? r row) (eq? c col))
                 (cell_val cell)
                 (lookup (tail board) row col)))))))

 ;; =========================
 ;; Conflict check:
 ;; #t if some cell in board has:
 ;;   - same value, and
 ;;   - same row OR same col OR same 3x3 block
 ;; =========================
 (define (conflicts? board row col val)
   (if (is_nil board)
       #f
       (let ([cell (head board)])
         (let ([r (cell_row cell)])
           (let ([c (cell_col cell)])
             (let ([v (cell_val cell)])
               (if (and (eq? v val)
                        (or (eq? r row)
                            (or (eq? c col)
                                (same_block? r c row col))))
                   #t
                   (conflicts? (tail board) row col val))))))))

 ;; =========================
 ;; Recursive backtracking solver over (row, col)
 ;; board: list of assignments
 ;; rows, cols = 0..8
 ;; =========================
 (define (solve_cell row col board)
   (if (eq? row 9)
       ;; All rows done: solved
       board
       (if (eq? col 9)
           ;; End of row: go to next row
           (solve_cell (+ row 1) 0 board)
           ;; Otherwise, try this cell
           (let ([existing (lookup board row col)])
             (if (eq? existing 0)
                 ;; Empty cell: try values 1..9
                 (let ([candidate 1])
                   (let ([solution (void)])
                     (begin
                       (while (and (&amp;lt; candidate 10)
                                   (eq? solution (void)))
                              (begin
				(if (conflicts? board row col candidate)
                                    ;; conflict, skip
                                    (set! solution solution)
                                    ;; no conflict, extend board and recurse
                                    (let ([s (solve_cell row
                                                         (+ col 1)
                                                         (cons (make_cell row col candidate)
                                                               board))])
                                      (if (eq? s (void))
                                          (set! solution solution)
                                          (set! solution s))))
				(set! candidate (+ candidate 1))))
                       solution)))
                 ;; Pre-filled cell: just move on
                 (solve_cell row (+ col 1) board))))))

 ;; =========================
 ;; Read initial board from input:
 ;; 81 integers, row-major, 0 = empty, 1..9 = given
 ;; Returns list of cells
 ;; =========================
 (define (read_board)
   (let ([board (void)])
     (let ([i 0])
       (begin
         (while (&amp;lt; i 9)
		(begin
                  (let ([j 0])
                    (while (&amp;lt; j 9)
			   (begin
			     (let ([v (read)])
                               (if (eq? v 0)
				   (set! board board)
				   (set! board (cons (make_cell i j v) board))))
			     (set! j (+ j 1)))))
                  (set! i (+ i 1))))
         board))))

 ;; =========================
 ;; Entry: read board, solve from (0,0), return solution
 ;; Solution is a list of (row col val) cells
 ;; =========================
 (let* ([board (read_board)]
        [solution (solve_cell 0 0 board)])
   (lookup solution 8 8)))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;the-full-language&quot;&gt;The Full Language&lt;/h3&gt;

&lt;p&gt;The final language you’ll implement will be this one. In comments,
I’ve also highlighted the sublanguages: for example, project 2
includes only numbers, input (read), binary plus, unary minus,
variable references and let binding. It grows to all of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R5&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(define (R5-exp? e)
  (match e
    ;; Project 2
    [(? fixnum?) #t]
    [&apos;(read) #t]
    [`(+ ,(? R5-exp? e0) ,(? R5-exp? e1)) #t]
    [`(- ,(? R5-exp? e)) #t]
    [(? symbol?) #t]
    [`(let ([,(? symbol? x) ,(? R5-exp? e)]) ,(? R5-exp? eb)) #t]
	;; Project 3
    [#t #t]
    [#f #t]
    [&apos;(void) #t]
    [`(- ,(? R5-exp? e0) ,(? R5-exp? e1)) #t]
    [`(and ,(? R5-exp? e0) ,(? R5-exp? e1)) #t]
    [`(or  ,(? R5-exp? e0) ,(? R5-exp? e1)) #t]
    [`(not ,(? R5-exp? e1)) #t]
    [`(,(? cmp? c) ,(? R5-exp? e0) ,(? R5-exp? e1)) #t]
    [`(if ,(? R5-exp? e-g) ,(? R5-exp? e-t) ,(? R5-exp? e-f)) #t]
    ;; Project 4
    [`(let* ([,(? symbol? xs) ,(? R5-exp? es)] ...) ,(? R5-exp? eb)) #t]
    [`(begin ,(? R5-exp?) ... ,(? R5-exp? ret)) #t]
    [`(while ,(? R5-exp? e-g) ,(? R5-exp? es) ...) #t]
    [`(make-vector ,(? R5-exp? len)) #t]
    [`(vector-ref ,(? R5-exp? v) ,(? fixnum? i)) #t]
    [`(vector-set! ,(? R5-exp? v) ,(? fixnum? i) ,(? R5-exp? e-v)) #t]
    [`(set! ,(? symbol? x) ,(? R5-exp? e)) #t]
    ;; Project 5
    [`(,(? R5-exp? e-f) ,(? R5-exp? a-args) ...) #t]
    [`(lambda (,(? symbol? xs) ...) ,(? R5-exp? e-body)) #t]
	[_ #f]))

(define (R5-defn? defn)
  (match defn
    ;; Project 5 adds multiple function definitions
    [`(define (,(? symbol? f) ,(? symbol? formals) ...)  ,(? R5-exp? e-b)) #t]
    [_ #f]))

(define (R5? p)
  (match p
    [`(program ,(? R5-defn? defns) ... ,(? R5-exp?)) #t]
    [_ #f]))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;the-compilers-structure&quot;&gt;The Compiler’s Structure&lt;/h3&gt;

&lt;p&gt;To get you booted up fast as possible, every single project is
designed the same way:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compile.rkt&lt;/code&gt; – Your pass implementations. You will edit functions provided here.
-&amp;gt; This is the &lt;em&gt;only&lt;/em&gt; file you will edit! The rest are read-only&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;irs.rkt&lt;/code&gt; – IR definitions and predicates like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;anf-program?&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c1-program?&lt;/code&gt;, etc. (see also typed/shrunk variants)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interpreters.rkt&lt;/code&gt; – Reference interpreters for several IRs (used by tests and for your own debugging).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system.rkt&lt;/code&gt; – System/ABI configuration, pass names, runtime filenames, output paths, etc.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main.rkt&lt;/code&gt; – Driver that runs all passes, can build a binary, and can launch a debug server.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test.rkt&lt;/code&gt; – Test harness. Runs isolation tests or end-to-end native tests depending on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-m&lt;/code&gt; mode.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runtime.c&lt;/code&gt; – Minimal runtime (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read_int64&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;print_int64&lt;/code&gt;, etc.).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test-programs/&lt;/code&gt; – Example programs (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.scm&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;input-files/&lt;/code&gt; – Input streams for programs (lines of integers).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;goldens/&lt;/code&gt; – Instructor goldens (IR snapshots, interpreter outputs, and stdout baselines).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You write your code in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;compile.rkt&lt;/code&gt;, which consists of a set of
&lt;em&gt;passes&lt;/em&gt;. Each pass transforms an input language into an output
language, and these intermediate languages (IRs) are codified via
predicates in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;irs.rkt&lt;/code&gt;. To define the meaning of each IR, we give an
interpreter for each in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;interpreters.rkt&lt;/code&gt;. For the compiler to be
correct, it needs to be the case that–for all input streams–the
compiler produces the same output stream across all intermediate
IRs. There is some system-specific stuff in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system.rkt&lt;/code&gt;, which takes
care of things like Linux vs. Mac ABI issues, specifying register
names, etc. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main.rkt&lt;/code&gt; file acts as a main compiler entrypoint,
and it carefully runs each pass of the compiler, checking predicates
before/after each pass and interpreting each IR, checking to ensure
consistency. This is a &lt;em&gt;huge&lt;/em&gt; win for debugging, in my opinion: you
&lt;em&gt;always&lt;/em&gt; want to localize errors to the proximate pass which causes
misinterpretation, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main.rkt&lt;/code&gt; seriously aids debugging in my
experience. There is also more comprehensive test infrastructure in
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test.rkt&lt;/code&gt;; this test script is invoked by the Python-based test
scripts in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test/&lt;/code&gt;. These tests check the behavior of the compiler on
the programs in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test-programs/&lt;/code&gt; directory, using the files from
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;input-files&lt;/code&gt; as inputs and comparing to the outputs in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;goldens/&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;why-is-this-course-unique-and-cool&quot;&gt;Why Is This Course Unique and Cool?&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;You build a &lt;strong&gt;real compiler&lt;/strong&gt;, all the way to actual x86-64
assembly.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Each IR has a corresponding interpreter, which is easy to find/read
and written in a familiar style, giving semantic clarity and
testable correctness.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The project is &lt;strong&gt;language scalable&lt;/strong&gt;, meaning that you can use it as
a base for building your own language. Of course, this is thanks to
Dr. Siek’s great “incremental” design.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It is &lt;strong&gt;fully testable across multiple passes&lt;/strong&gt;, which helps
anticipate the thing we all fear most about writing a compiler:
seeing a problem that is the ramification of far-away code from
higher up in the compilation pipeline.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It is written in a &lt;strong&gt;simple, pure recursive style&lt;/strong&gt;. Just plain old
pattern matching and recursion here, no need for any complex
abstractions.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;how-do-i-get-started&quot;&gt;How Do I Get Started?&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Familiarize yourself with the course webpage: https://kmicinski.com/cis531-f25&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If you don’t know Racket, start with project 1: https://kmicinski.com/cis531-f25/projects/1&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Otherwise, start with project 2: https://kmicinski.com/cis531-f25/projects/2&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;When you finish each project, move on to the next!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;When you’re done, start building your &lt;strong&gt;own&lt;/strong&gt; language. Consider
adding type (checking/inference), classes, more builtins, pattern
matching, continuations, exceptions, algebraic effects. The options
are myriad, but once you’ve finished projects 2-5, you’ve built a
whole compiler for a surprisingly expressive language.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;thank-you-to-the-national-science-foundation-and-others&quot;&gt;Thank you to the National Science Foundation and Others&lt;/h3&gt;

&lt;p&gt;If you like this work and live in the United States, please feel
commensurately less bad about paying your taxes. I made the whole
class free, at least as free as I could given practical
constraints. This class work on compilation is partially supported by
our &lt;a href=&quot;https://www.nsf.gov/awardsearch/show-award/?AWD_ID=2316159&amp;amp;HistoricalAwards=false&quot;&gt;NSF PPoSS
large&lt;/a&gt;,
which has already produced &lt;a href=&quot;https://arxiv.org/pdf/2411.14330&quot;&gt;many&lt;/a&gt;
&lt;a href=&quot;https://dl.acm.org/doi/pdf/10.1145/3721145.3730431&quot;&gt;cool&lt;/a&gt;
&lt;a href=&quot;https://dl.acm.org/doi/pdf/10.1145/3669940.3707274&quot;&gt;major&lt;/a&gt;
&lt;a href=&quot;https://ojs.aaai.org/index.php/AAAI/article/download/33665/35820&quot;&gt;results&lt;/a&gt;. In
subsequent explorations, I am hoping that I can use this class
compiler as a baseline for highly-scalable engines that reason about
programs. Given the simple, self-contained nature–and the presence of
per-pass interpreters and consistency testing–I see this as an
awesome potential baseline for cool extensions.&lt;/p&gt;

&lt;p&gt;My course is of course heavily inspired by Prof. Siek’s book and
course, along with inspiration from Thomas Gilray at Washington
State. Eight years ago, Tom and I took a spontaneous trip to see the
eclipse halfway across the country (skipping out on the ICSE ‘17
deadline basically); we discussed compiler design over a steamed
seafood buffet in Myrtle Beach after napping in a cheap motel, having
been awake for over 24 hours and feeling the eclipse had made it worth
it. We sketched out his whole compiler on that roadtrip, and ever
since that night eating steamed crabs, I wanted to build my own course
compiler. Now that I have, I am not sure it compares to waking up for
just four hours of twilight, only to consume copious amounts of butter
and shellfish as the brisk ocean air wisps over your face, the
closures and continuations softly washing rhythmically through the
conversation as you walk along the beach back to your $50 motel room.&lt;/p&gt;

&lt;p&gt;In closing, thanks for checking this out, this compiler was a ton of
fun to build. Even as someone who has some amount of expertise in
compiler design, building it and getting it 100% right (I hope!) was
such a rewarding experience. My real sincere hope is that it offers
students (and you!) a fun journey. If you end up doing anything this,
please get in touch: kkmicins@syr.edu. I’d love to see what you come
up with. Best wishes,&lt;/p&gt;

&lt;p&gt;Kristopher Micinski
– Syracuse, November, 2025&lt;/p&gt;
</description>
        <pubDate>Sun, 23 Nov 2025 00:00:00 -0500</pubDate>
        <link>/functional-programming/2025/11/23/build-a-language/</link>
        <guid isPermaLink="true">/functional-programming/2025/11/23/build-a-language/</guid>
        
        
        <category>functional-programming</category>
        
      </item>
    
      <item>
        <title>Why Tail-Recursive Functions are Loops</title>
        <description>&lt;p&gt;One story every computing enthusiast should hear is the lesson of
how loops and tail-recursion are equivalent. We like recursive
functions because they’re amenable to induction, and we can derive
them in a way that is in direct correspondence with the definition of
the datatype over which they recur. We like loops because they’re
fast and make intuitive sense as long as variables don’t change in too
tricky a way.&lt;/p&gt;

&lt;p&gt;In general, recursive functions are slower than loops because they
push stack frames: the performance of most programs today is dominated
by memory reads/writes. The data we touch the most lives in the
cache–we do &lt;em&gt;not&lt;/em&gt; want to evict a ton of stuff from the cache, under
any circumstance. In a direct-style implementation of a recursive
function, the recursive call &lt;em&gt;has&lt;/em&gt; to push a stack frame to remember
what to do once the function returns:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; Racket
(define (sum l)
  (if (empty? l)
      0
      (+ (first l) (sum (rest l)))))

// C 
int sum(int *l, int length) {
    if (length == 0)
        return 0;
    else
        return l[0] + sum(l + 1, length - 1);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When we get to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(+ (first l) (sum (rest l)))&lt;/code&gt;, we first call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(first
l)&lt;/code&gt; (which returns the first element). While we’re making that call,
we have to remember to come back and do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(sum (rest l))&lt;/code&gt;–to be fully
precise, we remember that we need to do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(rest l)&lt;/code&gt;, then take its
result &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; and call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(sum x)&lt;/code&gt;, remembering to come back and finally
take &lt;em&gt;that&lt;/em&gt; result and add it to the result of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(first l)&lt;/code&gt;. The reason
we have to do this is because we need to remember those partial
results (in this case the result of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(first l)&lt;/code&gt;): we have to store
them somewhere after all, and each time we make the recursive call, we
need to remember the result of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(first l)&lt;/code&gt; from &lt;em&gt;this&lt;/em&gt; call–we need
O(n) stack space for a list of size n.&lt;/p&gt;

&lt;p&gt;Of course, if we use iteration this all goes away:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; Racket
(define (sum l)
  (define x 0)
  (for ([elt l])
    (set! x (+ x elt)))
  x)

// C
int sum(const int *l, int length) {
    int x = 0;
    for (int i = 0; i &amp;lt; length; i++) {
        x += l[i];
    }
    return x;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We all have an intuitive sense of what the loop is doing: once we hit
the end of the loop, we do &lt;em&gt;not&lt;/em&gt; make a recursive call (we never issue
a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt; instruction in assembly), we simply &lt;em&gt;jump&lt;/em&gt; up to the
beginning of the loop. The key is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; is being used as an
&lt;em&gt;accumulator&lt;/em&gt;, growing a partial result in a &lt;em&gt;bottom-up&lt;/em&gt; fashion as
the computation proceeds, eventually yielding the final value at the
end. Instead of keeping partial results on the stack, the loop takes a
&lt;em&gt;constant&lt;/em&gt; amount of space but linear time.&lt;/p&gt;

&lt;p&gt;In a tail-recursive implementation, the rule is that every recursive
call must be a &lt;em&gt;tail&lt;/em&gt; call. Intuitively, a tail call is a call which
is “immediately returned.” More formally, a subexpression of an
expression is in tail position if the return value from that
expression is the return value from the whole expression. For example,
in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(if guard e-t e-f)&lt;/code&gt;, both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e-t&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e-f&lt;/code&gt; are in tail position,
but the guard is not: after we decide which branch to take, we’re
committed:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(define (foo ...)
  ...
  (if guard
    (f x y ...)
    (g z ...)))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once we finish executing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;guard&lt;/code&gt;, it would be &lt;em&gt;useless&lt;/em&gt; (but
&lt;strong&gt;correct&lt;/strong&gt;) to (a) push a stack frame, (b) wait on the result of the
subordinate call, and (c) merely return &lt;em&gt;that same result&lt;/em&gt;, because
all we’d be doing is &lt;em&gt;copying&lt;/em&gt; the return value from the callee and
propagating it back as the return value of the caller.  Being a tail
call is a syntactic property of a callsite: we (and the compiler) can
easily look at a piece of code and cheaply decide when a call is a
tail call versus not.&lt;/p&gt;

&lt;p&gt;This reasoning above generalizes to &lt;em&gt;any&lt;/em&gt; call expression in tail
position: &lt;em&gt;because a tail call will necessarily evaluate to its
result, administratively copying it up/down the stack is extensionally
a no-op&lt;/em&gt;. Now, the tail-recursive version uses a simple trick I teach
to all of my students: (a) identify an accumulator variable, (b)
instead of computing with the &lt;em&gt;result&lt;/em&gt; of the recursive call, compute
with the &lt;em&gt;current accumulator&lt;/em&gt;, (c) return the accumulator in the base
case:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; Racket
(define (sum l acc) ;; note: acc got added
  (if (empty? l)
      acc ;; this is the *true* return!
      (sum (rest l) (+ acc (first l)))))

// C -- we pass in length manually because we&apos;re using arrays
int sum(const int* l, int length, int acc) {
    if (length == 0) return acc;
    return sum(l + 1, length - 1, acc + l[0]);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Both of these functions are tail recursive: because the only recursive
call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sum&lt;/code&gt; is &lt;em&gt;also&lt;/em&gt; the return value from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sum&lt;/code&gt; (or, more
directly: because both calls to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sum&lt;/code&gt; are in tail position). Since the
compiler knows that these are tail calls, a compiler with tail-call
optimization will ensure that both of these tail calls compile into
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jmp&lt;/code&gt; statements–with zero implication on stack usage–rather than
the more burdensome (on the cache, stack, etc.) direct-style
calls. Something that should concern you is this: if the function is
using constant stack space, how are the variables being updated /
represented!? The answer is that the arguments get &lt;strong&gt;stomped over&lt;/strong&gt;,
and &lt;strong&gt;mutably updated&lt;/strong&gt;, yielding the &lt;em&gt;exact same performance profile
as a loop!&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Now time for an exercise, what about this program, can you convert it
to using tail-recursion?&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; return a pair (cons cell) of the number of even numbers,
;; and the number of odd numbers.
;; HINT: use multiple accumulators. 
(define (even-odd l)
  (if (empty? l)
      (cons 0 0)
      (let ([v (even-odd (rest l))])
            (if (first l)
                (cons (add1 (car v)) (cdr v))
                (cons (car v) (add1 (cdr v))))))))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What about &lt;em&gt;this&lt;/em&gt; program?&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; flattens a tree? into a list
;; It&apos;s hard because there are *two* calls to linearize--can you do anything?
(define (linearize t)
  (match t
    [&apos;empty &apos;()]
    [`(node ,v ,t0 ,t1) (append (list v) (linearize t0) (linearize t1))]))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;One surprising fact is that we can systematically compile &lt;em&gt;any&lt;/em&gt;
program so that &lt;em&gt;every&lt;/em&gt; call is a tail-call, by completely
transforming the program into &lt;a href=&quot;https://matt.might.net/articles/cps-conversion/&quot;&gt;continuation-passing-style
(CPS)&lt;/a&gt;, this
essentially &lt;em&gt;eliminates&lt;/em&gt; the stack. Indeed, some compilers for
functional languages work precisely this way: those languages
&lt;strong&gt;cannot&lt;/strong&gt; fall prey to a stack overflow, because they have
essentially traded a monolithic (efficient, array-like) stack for a
deeply-nested stack, strewn throughout the heap—because the
continuations will be heap-allocated and nested. There are various
exciting trade-offs here, but for now I will leave this as is–we will
continue next week.&lt;/p&gt;

</description>
        <pubDate>Fri, 01 Aug 2025 00:00:00 -0400</pubDate>
        <link>/functional-programming/2025/08/01/loops/</link>
        <guid isPermaLink="true">/functional-programming/2025/08/01/loops/</guid>
        
        
        <category>functional-programming</category>
        
      </item>
    
      <item>
        <title>Modern Deduction Post 1: Chain-Forward Computation</title>
        <description>&lt;p&gt;Our setting is logic programming, a field which attempts to design
programming languages whose semantics have a close relationship to
formal logic. The reason we might want to do this is that it suits our
application domain more precisely than an implementation in a
traditional programming language. Thus, using a logic programming
language allows us to write more obviously-correct code, and perhaps
even code that can be extracted cleanly from a certified
implementation. Alternatively, if we did it ourselves, we’d have to do
what our compiler (interpreter, …) would do anyway, so there’s no
sense in doing it manually. Unfortunately, when we see a powerful
tool, we are tempted to use it for everything: if our application is
not ultimately-suited to the operationalization strategy of the logic
programming engine we’re using, we simply obfuscate the issue in a
veneer of formalism and end up with leaky abstractions. This is, I
speculate, why logic programming languages have never caught on
broadly for general-purpose programming. In this blog, I will detail
the various trade-offs and implementation paradigms for modern logic
programming engines, starting from Datalog and with a focus on program
analysis.&lt;/p&gt;

&lt;p&gt;The history of logic is rich, and I will not attempt to recount it
all. Here I will focus on more restricted, application-specific
languages, especially Datalog and its derivatives. The specific
features of these languages, and the particulars of their
implementation, often dovetail with a “right place, right time”
effect. For example, &lt;a href=&quot;https://suif.stanford.edu/papers/pldi04.pdf&quot;&gt;Datalog backed by
BDDs&lt;/a&gt; was a significant
step forward in terms of production program analyses. More modern
implementations eschew BDDs for more explicit representations, but it
remains the case that engineers and computer scientists are on the
lookout for logic-programming-based approaches to hard problems,
especially those which deal intrinsically in the enumeration of large
state spaces.&lt;/p&gt;

&lt;p&gt;Perhaps one of logic programming’s most exciting motivations is
program analysis. Program analysis systems automatically prove
properties about, find bugs in, or simply help us understand our
programs. These can come in a variety of forms from on-demand
in-editor type-checking to whole-program (runs in microseconds),
context-sensitive points-to analysis (days). Program analyses are
notoriously hard to specify, and are especially hard to implement in a
way that provides a close relationship to the formal
specification. Additionally, program analyses often grapple with large
state spaces in practice to solve interesting problems, and require
some amount of thought regarding high-performance implementation.&lt;/p&gt;

&lt;h4 id=&quot;chain-forward-computation-and-datalog&quot;&gt;Chain-Forward Computation and Datalog&lt;/h4&gt;

&lt;p&gt;The central evaluation mechanism in Datalog, and its derivatives, is
to saturate a set of rules (e.g., Horn clauses) to a fixed point, to
obtain a knowledge database in some domain. We call the computation
“chain forward” because the evaluation of such languages is guided by
an ordering on knowledge, typically set inclusion (in the case of
traditional Datalogs). In these settings, we define an “immediate
consequence” operator, which tells us everything which must be known,
as a consequence of what we currently know; crucially, this operator
is typically monotonic: we do not lose knowledge over time, though we
will discuss some interesting departures from this
assumption. Applying this immediate consequence operator repeatedly
yields a stream of knowledge databases over time. Assuming the
immediate consequence operator is monotone, this stream of knowledge
databases over time forms an ascending chain according to the ordering
on knowledge.&lt;/p&gt;

&lt;p&gt;Datalog’s syntax consisting of “facts” and “rules.” Facts are “known
statements” and always have the following form: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R(c0, ...)&lt;/code&gt;, where
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R&lt;/code&gt; is a relation name (identifier) and the arguments are
constants. For example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;gt;(3,2)&lt;/code&gt; might be a fact, along with
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reaches(&quot;n0&quot;,&quot;n1&quot;)&lt;/code&gt;. But facts may not include variables, for
example: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reaches(&quot;n0&quot;,x)&lt;/code&gt; is disallowable as a fact, because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; is
not bounded in any way.&lt;/p&gt;

&lt;div class=&quot;language-scheme highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relation?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;symbol?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;atom?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;symbol?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;;; atomic lits are symbols&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; variables must be explicitly tagged, not &apos;x, but &apos;(var x)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;var?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;symbol?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;var-or-atom?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;atom?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;var?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; tuples are untagged&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;tuple?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;f&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;atom?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; facts add a relation name (otherwise how would we know it)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fact?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;f&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relation?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;atom?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; notice that ∧ is implicit in the body&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rule?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relation?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;head-rel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;var-or-atom?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&amp;lt;--&lt;/span&gt; 
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relation?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;body-rels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;var-or-atom?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s look at simplest interesting example: transitive closure. The
Datalog program (technically in Soufflé here) to implement transitive
closure &lt;a href=&quot;&quot;&gt;example (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tc.dl&lt;/code&gt;)&lt;/a&gt; is here (I elide some declarations):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.output path
.decl edge(x:number,y:number)
.decl path(x:number,y:number)
edge(1,2). edge(2,3). edge(3,5). edge(5,4). edge(4,1). edge(4,8).
path(x, y) :- edge(x, y).
path(x, y) :- path(x, z), edge(z, y).
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running this program in Soufflé (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;souffle tc.dl&lt;/code&gt;) yields an output
database, the transitively-closed graph, in the file &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;path.csv&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;datalog-cannot-search-disjunction-saturated-conjunctions-only&quot;&gt;Datalog cannot search (disjunction), saturated conjunctions only&lt;/h4&gt;

&lt;p&gt;Disjunctions in the head of a rule is disallowed: this is not
semantically within reach of Datalog. The following is invalid:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Q(x,...) ∨ R(x,...) ← P(...) ∧ R(...)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once we have more than one positive literal in a clause, we need a SAT
solver. SAT solvers combine search (“guess new things”) and deduction
(“derive consequences”); Datalog solvers only employ deduction. Both
SAT and Datalog engines share some overlapping ideas; for example,
both use indexing, to accelerate joins (Datalog) and for efficient
unit propagation (SAT). But (&amp;gt;2)-SAT is strictly harder than Datalog:
2-SAT can be written as Horn clauses (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Q ← R&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;¬R ∨ Q&lt;/code&gt;), but 3-SAT
and beyond are out of reach. By contrast, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;∧&lt;/code&gt; in the head of a rule
presents no serious semantic issue: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Q(x,...) ∧ R(x,...) ← ...&lt;/code&gt; can
easily be desugared into two rules: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Q(x,...) ← ...&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R(x,...) ←
...&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;SAT solvers have an importance difference from Datalog solvers: they
forget information. This is important because, while you can use
Datalog to do SAT solving just fine, you will pay a massive
performance due to the concomitant over-materialization induced by
enumerating all possibilities: you would be &lt;em&gt;literally materializing
O(2ⁿ)&lt;/em&gt;. Of course, there are languages that embrace such
cartoonishly-huge state spaces by design (answer-set programming, for
example), and their designs are subsequently guided around these
issues; indeed, grounding on-the-fly is an active research topic
within ASP.&lt;/p&gt;

&lt;p&gt;As an example, think about how you could write 5-clique:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;clique3(A, B, C) :-
    edge(A, B), edge(A, C), edge(B, C),
    A != B, A != C, B != C.
clique4(A, B, C, D) :-
    clique3(A, B, C),
    edge(A, D), edge(B, D), edge(C, D),
    A != D, B != D, C != D.
clique5(A, B, C, D, E) :-
    clique4(A, B, C, D),
    edge(A, E), edge(B, E), edge(C, E), edge(D, E),
    A != E, B != E, C != E, D != E.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;semi-naïve-evaluation&quot;&gt;Semi-Naïve Evaluation&lt;/h4&gt;

&lt;p&gt;One issue with the repeated application of the rules is that if we use
an explicit set-based representation of tuples, each iteration we’ll
“rediscover” all knowledge from every previous iteration—this
translates to additional data load, without commensurate knowledge
throughput. In Datalog, the solution is to employ a compilation into
an incrementalized IR, ala semi-naïve evaluation. For example, the
recursive rule in transitive closure becomes:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;path(x,z) ← path(x,y) ∧ edge(y,z)
          | 
   becomes| No Δ versions for edge as it is static
          |
Δpath(x,z) ← (Δpath(x,y) ∧ edge(y,z)) - path
i.e., 
Δpath(x,z) ∪= (Δpath(x,y) ⋈ edge(y,z)) - path
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The rule expands into a single rule, because the relation &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edge&lt;/code&gt; never
changes–thus, tracking a delta version would be
irrelevant. Additionally, we assume that at the end of each iteration,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Δpath&lt;/code&gt; is merged into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;path&lt;/code&gt;. In the more general case such as:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;g(y,x) ∧ p(x,z) ← p(x,y) ∧ g(y,z)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We would need to split the rule into several versions: one to join
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Δp&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;g&lt;/code&gt;, one to join &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;p&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Δg&lt;/code&gt;, and one to join &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Δp&lt;/code&gt; with
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Δg&lt;/code&gt;. Think about what would happen if we have only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Δp ⋈ Δg&lt;/code&gt;: if we
have facts &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(x,y)&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Δp&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(y,z)&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Δg&lt;/code&gt;, everything works
fine. But what happens if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(x,y)&lt;/code&gt; skips an iteration? It would be hard
to ensure that doesn’t happen (though some work certainly explores
this to a degree), and so we diversify our rules to enable us to catch
things in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Δp&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Δg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Previously, I mentioned the resulting rule would look something like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Δpath(x,z) ∪= (Δpath(x,y) ⋈ edge(y,z)) - path
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In fact, all rules within a fixedpoint (more specifically, an SCC of
rules) will have the structure:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ΔR(x...) ∪= (ΔR(x,...) ⋈ Q(y,...)) - R
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There is a crucial tacit point to be explained here: deduplication,
i.e., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;- R&lt;/code&gt; is dirt cheap when implemented thoughtfully, and it is
possible to parallelize nicely. There is no explicit scan of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R&lt;/code&gt; in
implementing subtraction, rather every rule generates a set of
possibly-new tuples, which are deduplicated in some efficient manner
to add to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ΔR&lt;/code&gt; at the end of each iteration, before emptying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ΔR&lt;/code&gt; in
preparation for the next iteration.&lt;/p&gt;

&lt;p&gt;I will not code up semi-naïve evaluation here, but will likely discuss
a general approach to forward differentation and incrementalization in
subsequent posts.&lt;/p&gt;

&lt;h4 id=&quot;relational-algebra&quot;&gt;Relational Algebra&lt;/h4&gt;

&lt;p&gt;The explicit focus on bound variables has made the above presentation
informal, as substitution was never defined. Indeed, substitution is
“where computation happens” here in much the same way as in the
λ-calculus. However, handling binders is a bit tedious, and it turns
out there is a better, more systematic way. In the same way that
category theory will avoid mentioning concrete points for products A ×
B, relational algebra will avoid mentioning explicitly-named points
for manipulating relations.&lt;/p&gt;

&lt;p&gt;The lack of explicit binders allows us to write an obviously-correct
(albeit slow) interpreter for a conjunctive query that produces sets
of tuples as its output:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; q: query?
;; db: hashmap from relation name ↦ ℘(Tuple)
;; returns a set of tuples
(define (interpret-query q db)
  (match q
    [`(literal-tuple ,es ...) (set es)]
    [`(scan ,R) (hash-ref db R)]
    [`(select from ,q+ where column ,n equals ,k)
     (list-&amp;gt;set (filter (lambda (x) (equal? (list-ref x n) k))
                        (set-&amp;gt;list (interpret-query q+ db))))]
    [`(,q0 ∪ ,q1) (set-union (interpret-query q0 db)
                             (interpret-query q1 db))]
    [`(,q0 ∩ ,q1) (set-intersect (interpret-query q0 db)
                                 (interpret-query q1 db))]
    [`(reorder ,q ,order ...)
     (let ([ts (set-&amp;gt;list (interpret-query q db))])
       (set-&amp;gt;list
        (map (λ (t) (map (λ (i) (list-ref t i)) order))
             ts)))]
    [`(project ,q to first ,n)
     (list-&amp;gt;set (map (λ (t) (take t n)) (set-&amp;gt;list (interpret-query q db))))]
    [`(,q0 ⋈ ,q1 on first ,N)
     (list-&amp;gt;set
      (foldl
       (λ (t0 tups)
         (foldl (λ (t1 tups)
                  (if (equal? (take t0 N) (take t1 N))
                      (set-add tups (append (take t0 N) (drop t0 N) (drop t1 N)))
                      tups))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The implementation is mostly standard: notice that ⋈ degenerates to
the cartesian product in the case that N=0 (since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(take t 0)&lt;/code&gt; returns
the empty list for all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t&lt;/code&gt;). We include only binary joins, k-ary joins
are typically decomposed into chains or trees of binary joins: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R ⋈ Q
⋈ S&lt;/code&gt; can be construed as either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(R ⋈ Q) ⋈ S&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R ⋈ (Q ⋈ S)&lt;/code&gt; (3 or
more joins would allow us to consider trees, too). Unfortunately, the
wrong choice could force the enumeration to explode: if a subordinate
join produces lots of junk which is later filtered out by the outer
join, we may end up doing more work than an alternative join
plan. Join planning–-the process of optimally deciding on a join
decomposition–is a challenging aspect of the implementation; for some
programs, &lt;em&gt;any&lt;/em&gt; particular static join plan is be inefficient, as
relation sizes dynamically evolve, the optimal join plan may shift as
well. While traditional databases put a lot of effort into query
planning, Datalog has taken a slightly different approach, with only
scant recent work exploring dynamic plans.&lt;/p&gt;

&lt;p&gt;With this implementation, we can write query to find us all of the
one-hop transitive edges: the query we want is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edge(x,y), path(y,z)&lt;/code&gt;,
which operationalizes to a join between edge and path; since we want
to line up the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y&lt;/code&gt;s we reorder &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edge&lt;/code&gt;, then reorder the join result
(to gather &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;z&lt;/code&gt;), then project the first two elements.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(interpret-query
 &apos;(project (reorder ((reorder (scan edge) 1 0) ⋈ (scan path) on first 1) 1 2 0)
           to first 2)
 (hash &apos;edge (set &apos;(a b) &apos;(b c) &apos;(c d) &apos;(b e))
       &apos;path (set &apos;(a b) &apos;(b c) &apos;(c d) &apos;(b e))))
;; yields (set &apos;(a e) &apos;(b d) &apos;(a c))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Assuming we’re willing to write programs in terms of relational
algebra, we can iteratively generate new tuples. An &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RA-rule?&lt;/code&gt; extends
a specific relation (recall we’re taking a point-free style) with the
result of a query. We can interpret rules by evaluating the query and
unioning the result set into the necessary relation. A program is a
set of rules, which we can evaluate by iteratively (to a fixed point)
applying all rules until we see no changes in the database.&lt;/p&gt;

&lt;div class=&quot;language-scheme highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;RA-rule?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relation?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;RA-query?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-rule&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match-define&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,R&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash-set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set-union&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash-ref&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-query&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-program&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;next-iteration&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;foldl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-rule&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;do-some-more&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;equal?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;next-iteration&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;do-some-more&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;next-iteration&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;do-some-more&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we can write small programs:&lt;/p&gt;

&lt;div class=&quot;language-scheme highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-program&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;edge&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;literal-tuple&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;edge&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;literal-tuple&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;edge&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;literal-tuple&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;edge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reorder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reorder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;edge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;⋈&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                     &lt;span class=&quot;nv&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next time, we’ll plan to talk a bit about how to systematically
compile our high-level rules into the RA plans, and discuss the
various trade-offs in doing so.&lt;/p&gt;

&lt;h4 id=&quot;the-full-code&quot;&gt;The full code&lt;/h4&gt;

&lt;p&gt;Is here in &lt;a href=&quot;https://gist.github.com/kmicinski/e31ef6f2526c21cb0ec968f0e260e4a0&quot;&gt;this gist&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-scheme highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;;; Relational algebra&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;lang&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;racket&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relation?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;symbol?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;atom?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;symbol?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;;; atomic lits are symbols&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; variables must be explicitly tagged, not &apos;x, but &apos;(var x)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;var?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;symbol?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;var-or-atom?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;atom?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;var?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; tuples are untagged&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;tuple?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;f&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;atom?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; facts add a relation name (otherwise how would we know it)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fact?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;f&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relation?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;atom?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; notice that ∧ is implicit in the body&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rule?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relation?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;head-rel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;var-or-atom?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&amp;lt;--&lt;/span&gt; 
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relation?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;body-rels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;var-or-atom?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; should all be true&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rule?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&amp;lt;--&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rule?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&amp;lt;--&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rule?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&amp;lt;--&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;edge&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rule?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&amp;lt;--&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;edge&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; RA queries&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;RA-query?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;literal-tuple&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;atom?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;es&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;;; scan a relation&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relation?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;RA-query?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;nv&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;column&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;nonnegative-integer?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;nv&quot;&gt;equals&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;atom?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
     &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;;; natural join on the first N columns, values must be equal&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;RA-query?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;⋈&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;RA-query?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;nonnegative-integer?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;RA-query?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;RA-query?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;RA-query?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∩&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;RA-query?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;;; reorder tuples&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reorder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;RA-query?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;nonnegative-integer?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;;; project the first n elements of tuples&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;RA-query?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;nonnegative-integer?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;;; need closed-world assumption&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;RA-query?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; q: query?&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; db: hashmap from relation name ↦ ℘(Tuple)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; returns a set of tuples&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-query&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;literal-tuple&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;es&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;es&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash-ref&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;q+&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;column&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;equals&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;list-&amp;gt;set&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;filter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;equal?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list-ref&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set-&amp;gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-query&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q+&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,q0&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;q1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set-union&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-query&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q0&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                             &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-query&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,q0&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∩&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;q1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set-intersect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-query&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q0&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                                 &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-query&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reorder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set-&amp;gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-query&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))])&lt;/span&gt;
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set-&amp;gt;list&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list-ref&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
             &lt;span class=&quot;nv&quot;&gt;ts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;list-&amp;gt;set&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set-&amp;gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-query&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,q0&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;⋈&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;q1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;list-&amp;gt;set&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;foldl&lt;/span&gt;
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t0&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;foldl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;equal?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t0&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set-add&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tups&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;take&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t0&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;drop&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t0&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;drop&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;t1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
                      &lt;span class=&quot;nv&quot;&gt;tups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;tups&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set-&amp;gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-query&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q1&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set-&amp;gt;list&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-query&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q0&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))]))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;RA-rule?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relation?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;RA-query?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;#f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-rule&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match-define&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;,R&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash-set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set-union&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash-ref&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-query&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;q&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-program&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;next-iteration&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;foldl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-rule&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;rules&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;do-some-more&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;equal?&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;next-iteration&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;do-some-more&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;next-iteration&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;do-some-more&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;;; relations: hash from relation names to their associated arities&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;;; herbrand-base is a list of atoms &lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;herbrand-universe&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relations&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;herbrand-base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;;; generate a cartesian product of arity n with atoms from herbrand-base&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(())&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;apply&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;append&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cons&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;lst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;herbrand-base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))))&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;foldl&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;λ&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash-set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash-ref&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relations&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash-keys&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;relations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-query&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reorder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reorder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;edge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;⋈&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;nv&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;&apos;edge&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
       &lt;span class=&quot;ss&quot;&gt;&apos;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;interpret-program&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;edge&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;literal-tuple&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;edge&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;literal-tuple&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;edge&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;literal-tuple&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;edge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;∪&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reorder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reorder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;edge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;⋈&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                     &lt;span class=&quot;nv&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</description>
        <pubDate>Sat, 11 May 2024 00:00:00 -0400</pubDate>
        <link>/modern-deduction/1</link>
        <guid isPermaLink="true">/modern-deduction/1</guid>
        
        
      </item>
    
      <item>
        <title>Modern Deduction Post 0: Prologue</title>
        <description>&lt;p&gt;Over the past few years, my collaborators and I have been exploring
the design of high-performance logic programming engines for a wide
variety of tasks, including program analysis (points-to analysis,
abstract interpretation), graph analytics (transitive closure,
PageRank), and security (binary code similarity, disassembly, and
decompilation). We (myself, my collaborators, and our students) have
engineered a variety of systems aiming for both (a) state-of-the-art
performance at the highest scale (shared-memory parallelism,
distribution via MPI, SIMD on GPUs, and GPU cluster computing) and (b)
semantic extensions (monotonic aggregation, algebraic data) to
Datalog.&lt;/p&gt;

&lt;p&gt;I will be chronicling our efforts (mostly the relevant background) in
this series of posts, Modern Deduction. I will plan to put out a post
once every month or two.&lt;/p&gt;

&lt;p&gt;Posts:&lt;/p&gt;

</description>
        <pubDate>Fri, 05 Apr 2024 00:00:00 -0400</pubDate>
        <link>/modern-deduction/0</link>
        <guid isPermaLink="true">/modern-deduction/0</guid>
        
        
      </item>
    
      <item>
        <title>Mid-Point Review Materials</title>
        <description>&lt;p&gt;This page holds my “year 3 review” materials for evaluation and
promotion at Syracuse University.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://kmicinski.com/assets/personal.pdf&quot;&gt;My detailed personal statement (including teaching and research statements) is here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://kmicinski.com/assets/cv.pdf&quot;&gt;My current CV is linked here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A (~22MB) zip file linked
&lt;a href=&quot;https://kmicinski.com/assets/year-3-review.zip&quot;&gt;here&lt;/a&gt; gives the full
review packet, including CV, papers, and my personal statement.&lt;/p&gt;
</description>
        <pubDate>Fri, 16 Dec 2022 00:00:00 -0500</pubDate>
        <link>/year-3-review</link>
        <guid isPermaLink="true">/year-3-review</guid>
        
        
      </item>
    
      <item>
        <title>Certifying Interpreters in Racket</title>
        <description>&lt;p&gt;When I began programming, I read a copy of Richard Steven’s “Programming in the UNIX Environment.” Ultimately, my early experimentations with C were a failure; however, I later read David Beazley’s “Python: Essential Reference,” and was quickly able to pick up the UNIX API via it’s much simpler (admittedly, largely due to Beazley’s writing) Python counterpart. After teaching my undergraduate PL courses in Scheme variants these past few years I have wondered if we can understand type theory’s operationalization (via proof objects) using a similar shift in perspective.&lt;/p&gt;

&lt;p&gt;Here, I rigorously define an interpreter which produces a certificate
of its own correctness—assuming you trust the correctness of our
metalanguage, which (in the interests of appeasing the more skeptical
among us) we treat as S-expression comparison. Here I use Racket, but
any similar dynamic language with matching (or, if in OO, virtual
methods) would work to illustrate the key ideas. I do use Racket’s
contracts to check certificates, though other implementations could
defer this to the end or even elide checking entirely.&lt;/p&gt;

&lt;h3 id=&quot;the-language&quot;&gt;The Language&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; Specification of IfArith&apos;s syntax as a Racket predicate
(define (expr? e)
  (match e
    [(? nonnegative-integer? n) #t]
    [(? symbol? x) #t]
    [`(let ,(? symbol? x) ,(? expr? e) ,(? expr? e-body))]
    [`(plus ,(? expr? e0) ,(? expr? e1)) #t]
    [`(not ,(? expr? e-guard)) #t]
    [`(if0 ,(? expr? e0) ,(? expr? e1) ,(? expr? e2)) #t]
    [_ #f]))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(define e0 &apos;(plus 2 1)) ;; 3
(define e1 &apos;(plus 1 (if0 0 1 2))) ;; 2
(define e2 &apos;(let x (plus 0 0) (plus x 1))) ;; 1 
(define e3 &apos;(let x (plus 0 (if0 (plus 0 0) 1 0)) (plus x 0))) ;; 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;the-proofs&quot;&gt;The Proofs&lt;/h3&gt;

&lt;p&gt;Now the tricky part: we need to think about what proofs for evaluation
of terms in our little language look like. To be precise about it, we
need to define a relation: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e, ρ ⇓ v&lt;/code&gt;, such that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e&lt;/code&gt; is an expression,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ρ&lt;/code&gt; is an environment (mapping variables to values) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v&lt;/code&gt; is a
value. To be constructive about it, we need to algebraically define a
structure representing proofs that the evaluation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ρ&lt;/code&gt;
evaluates to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v&lt;/code&gt;. Following the Scheme tradition of homoiconicity, we
represent proofs as S-expressions themselves; inference rules using
pattern matching over these S-expressions to mirror the natural
deduction (big-step) style in which we would write our semantics on
paper. As an example, here’s a derivation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(if0 0 (plus 1 1) 0)&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(⇓-if-true
  (⇓-const ----- 
         (0 ∅ ⇓ O))
  (⇓-plus
   (⇓-const -----
        (1 ∅ ⇓ (S O)))
   (⇓-const -----
          (1 ∅ ⇓ (S O)))
   (plus -----
      (= (+ (S O) (S O)) (S (S O))))
   -----
   ((plus 1 1) ∅ ⇓ (S (S O))))
  -----
  ((if0 0 (plus 1 1) 0) ∅ ⇓ (S (S O))))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Racket’s pattern matcher is, of course, very different than a more
elaborate matcher centered around higher-order unification in a
statically-typed setting. Manually explicating the unification becomes
a bit of a chore after a while; certainly a rebuke to the thought of
using this as a serious strategy for type theory, but at the same time
precisely the reason we’re doing it this way.&lt;/p&gt;

&lt;p&gt;Of course it would be possible (especially in such a simple semantics
as this) to define &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e, ρ ⇓ v&lt;/code&gt; using substitution to implement
variables; I explicitly materialize environments to (a) anticipate
closures (later) and (b) present a representational challenge upon
which I would like to expand a bit. Of course, using Racket as our
metalanguage, we could simply use hashes for environments. But
remember—we are trying to appease the pedants among us, thus
representation must be as symbolic as possible. Similarly, I represent
the naturals symbolically. I do allow myself a serious concession: I
internalize &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plus&lt;/code&gt;, as I elide &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fix&lt;/code&gt; in the source language. If this
disappoints you, I would say there’s no fundamental barrier; we could
easily-enough (via environments) implement application and then a
fixed-point combinator.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; naturals
(define (nat? n)
  (match n [&apos;O #t] [`(S ,(? nat? n)) #t] [_ #f]))

(define/contract (num-&amp;gt;nat n)
  (-&amp;gt; nonnegative-integer? nat?)
  (match n
    [0 &apos;O]
    [n `(S ,(num-&amp;gt;nat (- n 1)))]))

(define/contract (nat-&amp;gt;num n)
  (-&amp;gt; nat? nonnegative-integer?)
  (match n
    [&apos;O 0]
    [`(S ,x) (add1 (nat-&amp;gt;num x))]))

(define/contract (nat-add s0 s1)
  (-&amp;gt; nat? nat? nat?)
  (match s0
    [&apos;O s1]
    [`(S ,s0+) `(S ,(nat-add s0+ s1))]))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To represent environments we define (a) a predicate dictating valid
structure for environments and (b) a predicate, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(env-maps? ρ x v
pf)&lt;/code&gt;, which defines the structure of valid proofs showing that
environment &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ρ&lt;/code&gt; maps variable &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; to value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v&lt;/code&gt;. Both of these are in
the de-facto “trusted computing base,” in the sense that if your
definition of proofs is broken (i.e., don’t faithfully capture what
you want to prove) then it doesn’t matter that your interpreter
produces proofs. And, of course, this is the biggest drawback of using
an untyped language to do this—we only get some rough syntactic
checking, similar to tools such as Ott but not dependently-typed
languages or provers. To avoid completely defeating the purpose of our
exercise here, I have followed a bit of a trick to rely minimally on
Racket as a metatheory: because many objects internal to the semantics
(e.g., numbers, environments, and proofs) are represented purely
symbolically (as S-expressions), we primarily rely upon Racket for
S-expression equality and dispatch (matching). Aside from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plus&lt;/code&gt; our
semantics uses a very small subset of Racket: I believe essentially
either (equivalently) existential fixed-point logic (of a Herbrand
base comprising S-expressions) or constrained horn clauses (whose
background logic includes S-expression equality and
structurally-recursive addition).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; environments
(define (environment? ρ)
  (match ρ
    [&apos;∅ #t]
    [`(↦ ,(? environment? ρ+) ,(? symbol? x) ,(? value? v)) #t]
    [_ #f]))

;; environment lookup -- predicate (inductive defn.)
(define/contract (env-maps? pf ρ x v)
  (-&amp;gt; any/c environment? symbol? value? boolean?)
  (match pf
    [`(↦-hit
       ------
       (↦ ,ρ ,x0 ,v0))
     (and (equal? x0 x) (equal? v0 v))]
    [`(↦-miss
       ,next-pf
       -----
       (↦ ,ρ ,x0 ,_))
     (and (not (equal? x0 x))
          (env-maps? next-pf ρ x v))]
    [_ #f]))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(⇓ pf e ρ v)&lt;/code&gt; follows its natural deduction
counterpart (which I have not written down, but try to stylize via my
spacing). Our procedure checks the proof, recursively calling itself
to check subproofs—mirroring the top-down process you may follow on
a whiteboard to check the proof yourself, though Reynolds points out
that the order of sub-checks is inherited from the metalanguage (i.e.,
Racket’s control flow).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; proofs of evaluation
(define/contract (⇓ pf e ρ v)
  (-&amp;gt; any/c expr? environment? value? boolean?)
  (match pf
    ;; Const
    [`(⇓-const
       -----
       (,(? nonnegative-integer? n) ,ρ+ ⇓ ,v+))
     (and (equal? (num-&amp;gt;nat n) v) (equal? v v+) (equal? ρ+ ρ))]
   ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Checking proofs for constants is easy. The rest of the rules follow
their natural deduction counterparts; the tedious part is the
administrative overhead required to implement the store-passing
construction. Of course my code is a bit smelly here; the ad-hoc use
of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;consequent&lt;/code&gt; points to a much cleaner refactoring that elides using
pairs of a return value and its proof in favor of projecting the value
from the proof, but the point here is to stick to what I think I’d end
up with doing it in an interactive proof assistant.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    ;; Var
    [`(⇓-var ,proof-x-in-ρ
       -----
       (,(? symbol? x) ,(? environment? ρ+) ⇓ ,(? value? v+)))
    (and (equal? ρ+ ρ) (equal? v+ v) (env-maps? proof-x-in-ρ ρ x v))]
    ;; Let
    [`(⇓-let
       ,proof-e0
       ,proof-e1
       -----
       ((let ,x ,e0 ,e1) ,(? environment? ρ+) ⇓ ,(? value? v+)))
     (and (equal? v+ v) (equal? ρ+ ρ)
          (⇓ proof-e0 e0 ρ (last (consequent proof-e0)))
          (⇓ proof-e1 e1 `(↦ ,ρ ,x ,(last (consequent proof-e0)))
		                            (last (consequent proof-e1))))]
    ;; Plus
    [`(⇓-plus
       ,proof-e0
       ,proof-e1
       (plus ----- (= (+ ,v0+ ,v1+) ,v-r))
       -----
       ((plus ,e0 ,e1) ,ρ+ ⇓ ,v-r))
     #:when (and (equal? v-r v) (equal? ρ+ ρ))
     (define v0 (last (consequent proof-e0)))
     (define v1 (last (consequent proof-e1)))
     (and (⇓ proof-e0 e0 ρ v0)
          (⇓ proof-e1 e1 ρ v1)
          (equal? v0+ v0)
          (equal? v1+ v1)
          (equal? v-r (nat-add v0 v1)))]
    ;; Not
    [`(⇓-not-0
       ,proof-e0
       -----
       ((not ,e0) ,ρ ⇓ O))
     (define v0+ (match (consequent proof-e0) [`(,_ ,_ ⇓ ,v) v]))
     (and (equal? v0+ v) (not (equal? v &apos;O)) (⇓ proof-e0 e0 ρ v))]
    [`(⇓-not-1
       ,proof-e0
       -----
       ((not ,e0) ,ρ ⇓ (S O)))
     (define v0+ (match (consequent proof-e0) [`(,_ ,_ ⇓ ,v) v]))
     (and (equal? v0+ v) (equal? v &apos;O) (⇓ proof-e0 e0 ρ v))]
    ;; If-True
    [`(⇓-if-true
       ,proof-guard-true
       ,proof-e1-v-res
       -----
       ((if0 ,e0 ,e1 ,e2) ,ρ ⇓ ,v))
     (match (consequent proof-guard-true)
       [`(,_ ,_ ⇓ O)
        (and (⇓ proof-guard-true e0 ρ &apos;O)
             (⇓ proof-e1-v-res e1 ρ v))])]
    ;; If-False
    [`(⇓-if-false
       ,proof-guard-false
       ,proof-e1-v-res
       -----
       ((if0 ,e0 ,e1 ,e2) ,ρ ⇓ ,v+))
     #:when (equal? v+ v)
     (match (consequent proof-guard-false)
       [`(,_ ,_ ⇓ ,n)
        (and (not (equal? n &apos;O))
             (⇓ proof-guard-false e0 ρ n)
             (⇓ proof-e1-v-res e1 ρ v))])]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;the-programs&quot;&gt;The Programs&lt;/h3&gt;

&lt;p&gt;Compared to the checking, writing the proofs is surprisingly
straightforward—even pleasant (okay; maybe not pleasant). A common
idiom when writing certified (proof-backed) code is the notion of
returning an existential, i.e., a witness alongside its proof. Of
course, the key challenge in writing certified code is convincing
yourself of its correctness.  There are a variety of ways you could do
this: you could inspect the output of the evaluator I write and ensure
that they match the specification, for example. However, for full
clarity, I will use Racket’s contract system, which allows dynamic
checking—this allows us to check the correctness of our evaluators
as we go, but of course won’t prove correctness across all runs, and
using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;define/contract&lt;/code&gt; also interposes the check at &lt;em&gt;every&lt;/em&gt; callsite
(a serious overhead), though I am sure you can use your imagination
about how this could be made faster.&lt;/p&gt;

&lt;p&gt;Let’s start with environments, writing a function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(lookup ρ x)&lt;/code&gt;,
which returns a proof that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; returns some value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v&lt;/code&gt;–if it doesn’t,
we would just throw a dynamic error due to a match failure–we are
posting a proof exists. We can write a contract to ensure that the
code we use to do this is correct. Racket’s default arrow contract
combinator, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&amp;gt;&lt;/code&gt;, is not powerful enough to express dependent
contracts, where a property of the result depends on one of the
inputs. However, Racket’s more powerful &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&amp;gt;i&lt;/code&gt; does allow dependent
contracts, allowing us to write a version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lookup&lt;/code&gt; which both
computes what we want and checks to ensure its correctness:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; decision procedure for lookup -- returns witness and proof of inclusion
(define/contract (lookup ρ x)
        ;; v---- domain ----v
    (-&amp;gt;i ([ρ environment?] [x symbol?])
        ;; range -- produces a proof dependent on ρ,x
         [result (ρ x)
                 (match-lambda [`(,(? value? v) . ,pf) (env-maps? pf ρ x v)]
                               [_ #f])])
  (match ρ
    [`(↦ ,ρ1 ,x1 ,v) #:when (equal? x1 x)
                     `(,v . (↦-hit ------ (↦ ,ρ ,x ,v)))]
    [`(↦ ,ρ1 ,x1 ,v) #:when (not (equal? x1 x))
                     (match (lookup ρ1 x)
                       [`(,v . ,pf)
                        `(,v . (↦-miss ,pf ----- (↦ ,ρ1 ,x1 ,v)))])]))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, the interpreter itself—unadorned by the ceremony and
pedantics of low-level unification checking—is surprisingly
unintimidating and to-the-point.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; produce a value alongside a proof of its correctness
(define/contract (eval e ρ)
  ;; contract: returns pair of value and proof of its derivation
  (-&amp;gt;i ([e expr?] [ρ environment?])
       [result (e ρ)
               (lambda (witness-pf) (match witness-pf
                                      [`(,(? value? v) . ,pf) (⇓ pf e ρ v)]
                                      [_ #f]))])
  (match e
    [(? nonnegative-integer? n)
     (cons (num-&amp;gt;nat n)
           `(⇓-const
             -----
             (,n ,ρ ⇓ ,(num-&amp;gt;nat n))))]
    [(? symbol? x)
     (match (lookup ρ x)
       [`(,v . ,pf)
        (cons v `(⇓-var
                  ,pf
                  -----
                  (,x ,ρ ⇓ ,v)))])]
    [`(let ,x ,e ,eb)
     (match (eval e ρ)
       [`(,v . ,pf-e)
        (match (eval eb `(↦ ,ρ ,x ,v))
          [`(,v-res . ,pf-v)
           (cons v-res
                 `(⇓-let
                   ,pf-e
                   ,pf-v
                   -----
                   ((let ,x ,e ,eb) ,ρ ⇓ ,v-res)))])])]
    [`(plus ,e0 ,e1)
     (match-define `(,v0 . ,pf-v0) (eval e0 ρ))
     (match-define `(,v1 . ,pf-v1) (eval e1 ρ))
     (define v-res (nat-add v0 v1))
     (cons v-res
           `(⇓-plus
             ,pf-v0
             ,pf-v1
             (plus ----- (= (+ ,v0 ,v1) ,v-res))
             -----
             ((plus ,e0 ,e1) ,ρ ⇓ ,v-res)))]
    [`(not ,e)
     (match (eval e ρ)
       [`(0 . ,pf-e)
        (cons &apos;(S O)
              `(⇓-not-1
                ,pf-e
                -----
                ((not ,e) ρ ⇓ (S O))))]
       [`(,v0 . ,pf-e)
        (cons &apos;O
              `(⇓-not-0
                ,pf-e
                -----
                ((not ,e) ρ ⇓ O)))])]
    [`(if0 ,e0 ,e1 ,e2)
     (match (eval e0 ρ)
       [`(O . ,pf-e0)
        (match (eval e1 ρ)
          [`(,v . ,pf-v)
           (cons v
                 `(⇓-if-true
                   ,pf-e0
                   ,pf-v
                   -----
                   ((if0 ,e0 ,e1 ,e2) ,ρ ⇓ ,v)))])]
       [`(,n . ,pf-e0)
        (match (eval e2 ρ)
          [`(,v . ,pf-v)
           (cons v
                 `(⇓-if-false
                   ,pf-e0
                   ,pf-v
                   -----
                   ((if0 ,e0 ,e1 ,e2) ,ρ ⇓ ,v)))])])]))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;visualizing-our-proofs&quot;&gt;Visualizing our Proofs&lt;/h3&gt;

&lt;p&gt;Alright, so now our interpreter writes proofs–what do they look like?
Thankfully, we used S-expressions.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; nice latex; comment out the labels by adding a % before \\tiny
(define (pf-&amp;gt;tex pf)
  (define name (first pf))
  (define antecedents (reverse (list-tail (reverse (list-tail (cdr pf) 0)) 2)))
  (foldr
   (lambda (k v acc) (string-replace acc k v))
   (format &quot;{{\\tiny \\textsc{ ~a }} \n \\frac{ ~a }{ \\texttt{ ~a } }}&quot;
           name
           (string-join (map pf-&amp;gt;tex antecedents) &quot;\\,&quot;)
           (consequent pf))
   &apos;(&quot;⇓&quot; &quot;∅&quot; &quot;↦&quot;)
   &apos;(&quot;\\ensuremath{\\Downarrow}&quot; &quot;\\ensuremath{\\emptyset}&quot; 
     &quot;\\ensuremath{\\mapsto}&quot;)))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here’s the complete derivation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;((plus 1 (if0 0 1 2)))&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/plus-1.png&quot; alt=&quot;Proof of ((plus 1 (if0 0 1 2)))&quot; style=&quot;width:650px&quot; class=&quot;post-image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And a longer program where I had to remove the rule names in
rendering…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/longproof.png&quot; alt=&quot;Longer proof&quot; style=&quot;width:650px&quot; class=&quot;post-image&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;metatheoretic-concessions-for-the-working-programmer&quot;&gt;Metatheoretic Concessions for the Working Programmer&lt;/h3&gt;

&lt;p&gt;Obviously we would never write an interpreter in Racket the way we did
above: there’s too much extraneous math (i.e., the proof objects). I
think it’s surprising, though, to see how much more direct the code
becomes by (a) erasing the proofs, (b) implementing the environment as
hashes, and (c) relying upon racket’s built-in representation of
numbers. The biggest burden in my implementation is obviously (a), as
I have explicated the proofs via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cons&lt;/code&gt;. Tighter implementations exist
that would hide the ugliness via (say) monads. Eliminating proofs also
eliminates a lot of administrative matching and in some places allows
to make tail calls to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eval&lt;/code&gt; where we couldn’t before, giving us a
textbook metacircular interpreter. I think it is interesting to see
just how directly a translation it is: I systematically removed each
feature (in the same way an extractor would) to achieve the simpler
implementation.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(define (eval-simpl e ρ)
  (match e
    [(? nonnegative-integer? n) n]
    [(? symbol? x) (hash-ref ρ x)]
    [`(let ,x ,e ,eb) (eval-simpl eb (hash-set ρ x (eval-simpl e ρ)))]
    [`(plus ,e0 ,e1) (+ (eval-simpl e0 ρ) (eval-simpl e1 ρ))]
    [`(not ,e)
     (match (eval-simpl e ρ)
       [0 1]
       [_ 0])]
    [`(if0 ,e0 ,e1 ,e2)
     (match (eval-simpl e0 ρ)
       [0 (eval-simpl e1 ρ)]
       [_ (eval-simpl e2 ρ)])]))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

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

&lt;p&gt;Do I think this is the future of dependently typed programming? Of
anything? Perhaps both no. Racket is not a particularly appealing
implementation language for type theory and its pattern matching is
not designed to scale to settings where higher-order unification is of
concern to the user. Similarly, this code has serious algorithmic
inefficiencies; plenty of the proof checking could be memoized, and
perhaps some simple contract trick would achieve this (though other
evaluation strategies could, e.g., use tabling in the metatheory). I
largely wrote this up to motivate my thoughts on (the potential of)
explaining the operationalization of proof objects to students as an
extension of operational semantics in the untyped setting I teach in
my class. Perhaps this will help someone draw connections between
operational semantics and proof objects, though I hesitate to say type
theory, broadly.&lt;/p&gt;

&lt;p&gt;Ultimately I did manage to find a lot of bugs in my implementation of
the interpreter using the contracts. Obviously, though, I was driving
the process by generating terms and not using a systematic methodology
of proving the correctness–I have tried to say that the interpreter
generates certificates, but it is of course not certified. It’s a fun
exercise, though–you can read the full code yourself below. I think
there are a few follow ups that could be done from here if you are
interested in experimenting with the code. Adding closures and
application, for example, should not be too hard; I may illustrate
that in my course next term.&lt;/p&gt;

&lt;p&gt;Thanks to Quinn Wilton for some corrections to the phrasing in this
post.&lt;/p&gt;

&lt;h3 id=&quot;the-code&quot;&gt;The Code&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;;; self-certifying interpreters, summer 2022, kris micinski
#lang racket

;; naturals
(define (nat? n)
  (match n [&apos;O #t] [`(S ,(? nat? n)) #t] [_ #f]))

(define/contract (num-&amp;gt;nat n)
  (-&amp;gt; nonnegative-integer? nat?)
  (match n
    [0 &apos;O]
    [n `(S ,(num-&amp;gt;nat (- n 1)))]))

(define/contract (nat-&amp;gt;num n)
  (-&amp;gt; nat? nonnegative-integer?)
  (match n
    [&apos;O 0]
    [`(S ,x) (add1 (nat-&amp;gt;num x))]))

(define/contract (nat-add s0 s1)
  (-&amp;gt; nat? nat? nat?)
  (match s0
    [&apos;O s1]
    [`(S ,s0+) `(S ,(nat-add s0+ s1))]))

;; values are nats
(define value? nat?)

;; expressions
(define (expr? e)
  (match e
    [(? nonnegative-integer? n) #t]
    [(? symbol? x) #t]
    [`(let ,(? symbol? x) ,(? expr? e) ,(? expr? e-body)) #t]
    [`(plus ,(? expr? e0) ,(? expr? e1)) #t]
    [`(not ,(? expr? e-guard)) #t]
    [`(if0 ,(? expr? e0) ,(? expr? e1) ,(? expr? e2)) #t]
    [_ #f]))

;; environments
(define (environment? ρ)
  (match ρ
    [&apos;∅ #t]
    [`(↦ ,(? environment? ρ+) ,(? symbol? x) ,(? value? v)) #t]
    [_ #f]))

;; environment lookup -- predicate (inductive defn.)
(define/contract (env-maps? pf ρ x v)
  (-&amp;gt; any/c environment? symbol? value? boolean?)
  (match pf
    [`(↦-hit
       ------
       (↦ ,ρ ,x0 ,v0))
     (and (equal? x0 x) (equal? v0 v))]
    [`(↦-miss
       ,next-pf
       -----
       (↦ ,ρ ,x0 ,_))
     (and (not (equal? x0 x))
          (env-maps? next-pf ρ x v))]
    [_ #f]))

;; decision procedure for lookup -- returns witness and proof of inclusion
(define/contract (lookup ρ x)
        ;; v---- domain ----v
    (-&amp;gt;i ([ρ environment?] [x symbol?])
        ;; range -- produces a proof dependent on ρ,x
         [result (ρ x)
                 (lambda (witness-pf) (match witness-pf
                                        [`(,(? value? v) . ,pf) (env-maps? pf ρ x v)]
                                        [_ #f]))])
  (match ρ
    [`(↦ ,ρ1 ,x1 ,v) #:when (equal? x1 x)
                     `(,v . (↦-hit ------ (↦ ,ρ ,x ,v)))]
    [`(↦ ,ρ1 ,x1 ,v) #:when (not (equal? x1 x))
                     (match (lookup ρ1 x)
                       [`(,v . ,pf)
                        `(,v . (↦-miss ,pf ----- (↦ ,ρ1 ,x1 ,v) ))])]))

; (lookup &apos;(↦ (↦ ∅ x O) y (S O)) &apos;x)

;; we will now follow the style &apos;(name atecedent0 ... ----- consequent)
(define (consequent judgement) (last judgement))

;; predicate -- inductive definition of evaluation relation
(define/contract (⇓ pf e ρ v)
  (-&amp;gt; any/c expr? environment? value? boolean?)
  (match pf
    ;; Const
    [`(⇓-const
       -----
       (,(? nonnegative-integer? n) ,ρ+ ⇓ ,v+))
     #:when (and (equal? (num-&amp;gt;nat n) v) (equal? ρ+ ρ) (equal? v v+))
     #t]
    ;; Var
    [`(⇓-var ,proof-x-in-ρ
       -----
       (,(? symbol? x) ,(? environment? ρ+) ⇓ ,(? value? v+)))
     #:when (and (equal? ρ+ ρ) (equal? v+ v))
     (env-maps? proof-x-in-ρ ρ x v)]
    ;; Let
    [`(⇓-let
       ,proof-e0
       ,proof-e1
       -----
       ((let ,(? symbol? x) ,(? expr? e0) ,(? expr? e1)) ,(? environment? ρ+) ⇓ ,(? value? v+)))
     #:when (equal? v+ v) (equal? ρ+ ρ)
     (and (⇓ proof-e0 e0 ρ (last (consequent proof-e0)))
          (⇓ proof-e1 e1 `(↦ ,ρ ,x ,(last (consequent proof-e0))) (last (consequent proof-e1))))]
    ;; Plus
    [`(⇓-plus
       ,proof-e0
       ,proof-e1
       (plus ----- (= (+ ,v0+ ,v1+) ,v-r))
       -----
       ((plus ,e0 ,e1) ,ρ+ ⇓ ,v-r))
     #:when (and (equal? v-r v) (equal? ρ+ ρ))
     (define v0 (last (consequent proof-e0)))
     (define v1 (last (consequent proof-e1)))
     (and (⇓ proof-e0 e0 ρ v0)
          (⇓ proof-e1 e1 ρ v1)
          (equal? v0+ v0)
          (equal? v1+ v1)
          (equal? v-r (nat-add v0 v1)))]
    ;; Not
    [`(⇓-not-0
       ,proof-e0
       -----
       ((not ,e0) ,ρ ⇓ O))
     (define v0+ (match (consequent proof-e0) [`(,_ ,_ ⇓ ,v) v]))
     (and (equal? v0+ v) (not (equal? v &apos;O)) (⇓ proof-e0 e0 ρ v))]
    [`(⇓-not-1
       ,proof-e0
       -----
       ((not ,e0) ,ρ ⇓ (S O)))
     (define v0+ (match (consequent proof-e0) [`(,_ ,_ ⇓ ,v) v]))
     (and (equal? v0+ v) (equal? v &apos;O) (⇓ proof-e0 e0 ρ v))]
    ;; If-True
    [`(⇓-if-true
       ,proof-guard-true
       ,proof-e1-v-res
       -----
       ((if0 ,e0 ,e1 ,e2) ,ρ ⇓ ,v))
     (match (consequent proof-guard-true)
       [`(,_ ,_ ⇓ O)
        (and (⇓ proof-guard-true e0 ρ &apos;O)
             (⇓ proof-e1-v-res e1 ρ v))])]
    ;; If-False
    [`(⇓-if-false
       ,proof-guard-false
       ,proof-e1-v-res
       -----
       ((if0 ,e0 ,e1 ,e2) ,ρ ⇓ ,v+))
     #:when (equal? v+ v)
     (match (consequent proof-guard-false)
       [`(,_ ,_ ⇓ ,n)
        (and (not (equal? n &apos;O))
             (⇓ proof-guard-false e0 ρ n)
             (⇓ proof-e1-v-res e1 ρ v))])]
    [_ #f]))

;;
;; Self-certifying interpreter
;;

;; produce a value alongside a proof of its correctness
(define/contract (eval e ρ)
  ;; contract: returns pair of value and proof of its derivation
  (-&amp;gt;i ([e expr?] [ρ environment?])
       [result (e ρ)
               (lambda (witness-pf) (match witness-pf
                                      [`(,(? value? v) . ,pf) (⇓ pf e ρ v)]
                                      [_ #f]))])
  (match e
    [(? nonnegative-integer? n)
     (cons (num-&amp;gt;nat n)
           `(⇓-const
             -----
             (,n ,ρ ⇓ ,(num-&amp;gt;nat n))))]
    [(? symbol? x)
     (match (lookup ρ x)
       [`(,v . ,pf)
        (cons v `(⇓-var
                  ,pf
                  -----
                  (,x ,ρ ⇓ ,v)))])]
    [`(let ,x ,e ,eb)
     (match (eval e ρ)
       [`(,v . ,pf-e)
        (match (eval eb `(↦ ,ρ ,x ,v))
          [`(,v-res . ,pf-v)
           (cons v-res
                 `(⇓-let
                   ,pf-e
                   ,pf-v
                   -----
                   ((let ,x ,e ,eb) ,ρ ⇓ ,v-res)))])])]
    [`(plus ,e0 ,e1)
     (match-define `(,v0 . ,pf-v0) (eval e0 ρ))
     (match-define `(,v1 . ,pf-v1) (eval e1 ρ))
     (define v-res (nat-add v0 v1))
     (cons v-res
           `(⇓-plus
             ,pf-v0
             ,pf-v1
             (plus ----- (= (+ ,v0 ,v1) ,v-res))
             -----
             ((plus ,e0 ,e1) ,ρ ⇓ ,v-res)))]
    [`(not ,e)
     (match (eval e ρ)
       [`(0 . ,pf-e)
        (cons &apos;(S O)
              `(⇓-not-1
                ,pf-e
                -----
                ((not ,e) ρ ⇓ (S O))))]
       [`(,v0 . ,pf-e)
        (cons &apos;O
              `(⇓-not-0
                ,pf-e
                -----
                ((not ,e) ρ ⇓ O)))])]
    [`(if0 ,e0 ,e1 ,e2)
     (match (eval e0 ρ)
       [`(O . ,pf-e0)
        (match (eval e1 ρ)
          [`(,v . ,pf-v)
           (cons v
                 `(⇓-if-true
                   ,pf-e0
                   ,pf-v
                   -----
                   ((if0 ,e0 ,e1 ,e2) ,ρ ⇓ ,v)))])]
       [`(,n . ,pf-e0)
        (match (eval e2 ρ)
          [`(,v . ,pf-v)
           (cons v
                 `(⇓-if-false
                   ,pf-e0
                   ,pf-v
                   -----
                   ((if0 ,e0 ,e1 ,e2) ,ρ ⇓ ,v)))])])]))

;; nice latex; comment out the labels by adding a % before \\tiny
(define (pf-&amp;gt;tex pf)
  (define name (first pf))
  (define antecedents (reverse (list-tail (reverse (list-tail (cdr pf) 0)) 2)))
  (foldr
   (lambda (k v acc) (string-replace acc k v))
   (format &quot;{{\\tiny \\textsc{ ~a }} \n \\frac{ ~a }{ \\texttt{ ~a } }}&quot;
           name
           (string-join (map pf-&amp;gt;tex antecedents) &quot;\\,&quot;)
           (consequent pf))
   &apos;(&quot;⇓&quot; &quot;∅&quot; &quot;↦&quot;)
   &apos;(&quot;\\ensuremath{\\Downarrow}&quot; &quot;\\ensuremath{\\emptyset}&quot; &quot;\\ensuremath{\\mapsto}&quot;)))

(define (derive e)
  (displayln (pf-&amp;gt;tex (cdr (eval e &apos;∅)))))

;; examples

;(derive &apos;(let x (plus 0 (if0 (plus 0 0) 1 0)) (plus x 0)))
;(derive &apos;(plus 1 (if0 0 1 2)))
;(derive &apos;(let x (plus 0 0) (plus x 1)))

(define (eval-simpl e ρ)
  (match e
    [(? nonnegative-integer? n) n]
    [(? symbol? x) (hash-ref ρ x)]
    [`(let ,x ,e ,eb)
     (eval-simpl eb (hash-set ρ x (eval-simpl e ρ)))]
    [`(plus ,e0 ,e1) (+ (eval-simpl e0 ρ) (eval-simpl e1 ρ))]
    [`(not ,e)
     (match (eval-simpl e ρ)
       [0 1]
       [_ 0])]
    [`(if0 ,e0 ,e1 ,e2)
     (match (eval-simpl e0 ρ)
       [0 (eval-simpl e1 ρ)]
       [_ (eval-simpl e2 ρ)])]))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</description>
        <pubDate>Sun, 14 Aug 2022 00:00:00 -0400</pubDate>
        <link>/certifying-interpreters</link>
        <guid isPermaLink="true">/certifying-interpreters</guid>
        
        
        <category>dependent-types,</category>
        
        <category>functional-programming,</category>
        
        <category>theorem-proving</category>
        
      </item>
    
      <item>
        <title>Why I hope you&apos;ll submit to Scheme Workshop</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://thomas.gilray.org/scheme-2019/&quot;&gt;&lt;strong&gt;Link to this year’s Scheme Workshop CFP&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This year marks the twentieth anniversary of the workshop on &lt;a href=&quot;http://www.schemeworkshop.org/&quot;&gt;Scheme
and Functional Programming&lt;/a&gt;. The
Scheme Workshop represents a diverse community of hackers, academics,
and enthusiasts. The workshop offers a forum to share insights,
experience, and technical developments of and within the Scheme family
of programming languages. Rather than focus on a specific
implementation or community, workshop attendees are united by an
appreciation for succinct expression of novel ideas realized via
programming. The submission deadline is &lt;strong&gt;May 24th, 2019&lt;/strong&gt;, I hope
you’ll help us celebrate by submitting a paper!&lt;/p&gt;

&lt;h4 id=&quot;what-is-scheme-workshop&quot;&gt;What is Scheme Workshop?&lt;/h4&gt;

&lt;p&gt;The Scheme Workshop website describes it as a…&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Yearly meeting of programming language practitioners who share an
  aesthetic sense embodied by the Algorithmic Language Scheme:
  universality through minimalism, and flexibility through rigorous
  design.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here’s my personal take. I love Scheme Workshop because it brings
together a group of people with a truly unique perspective on
programming. We represent a diverse background, but a shared vision:
to distill insights about programming to their most economic
presentation. We appreciate thoughtful, comprehensible solutions to
challenging problems. We challenge ourselves to step outside of our
boundaries and build fundamentally new paradigms for expressing
ideas. Our mission is to build a community where we foster diversity,
education, and support each other in pursuit of these ideals.&lt;/p&gt;

&lt;p&gt;Scheme Workshop is unique in that it is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Open to everyone who cares about Scheme-ish ideas&lt;/strong&gt;. Instead of
   focusing on promoting the most cutting edge results, Scheme
   Workshop centers around thoughtful discussions relating to unique
   ideas that embody the ethos of Scheme. You don’t have to be an
   academic to attend; in fact, we have a rich history of
   participation from hobbyists and industrial attendees.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Non-archival and open access&lt;/strong&gt;. We aim to support and foster unique
  ideas. Naturally, some of these ideas may grow into work
  eventually submitted to research conferences. Scheme Workshop
  provides a platform for researchers to get perspective from the
  Scheme community on their work at all stages of development. While
  we publish a technical report of submitted papers, submission to
  Scheme Workshop does not preclude subsequent submission to
  archival research conferences. In fact, we see Scheme Workshop as
  an ideal proving ground for groundbreaking research ideas. We hope
  that the discussions generated by the presentation of those ideas
  at Scheme Workshop will productively inform the authors’
  scholarship.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Supportive of off-the-wall ideas&lt;/strong&gt;. There are some ideas that
  are really interesting, kind of zany, and just inspire us in a
  deep way we can’t quite put our finger on. These ideas aren’t
  necessarily the kind that would fit well at a programming-oriented
  conference, but they might not be a good fit for research
  conferences either. Scheme Workshop is a perfect venue for these
  kinds of ideas. You’ll find like-minded people who enjoy
  challenging their perspectives on what programming even means.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;A great place for your first paper&lt;/strong&gt;. We place an emphasis on
  giving thoughtful, high-quality, and friendly reviews. We also
  have a strong appreciation for “half-baked” ideas. When I was a
  beginning PhD student, submitting to so-called top conferences
  often felt overwhelming. Scheme Workshop wants to help budding
  researchers develop their writing and presentation. Similarly, we
  realize that great ideas can come from people in industry, the
  open-source community, or the broader hobbyist community. We work
  hard to ensure that their ideas are taken seriously and give them
  the feedback they deserve.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;what-about-racket-haskell-clojure-sml-c-etc&quot;&gt;What about Racket, Haskell, Clojure, SML, C++, etc…?&lt;/h4&gt;

&lt;p&gt;The language isn’t what’s important, it’s the idea. We want the
workshop to be filled with exciting talks that broaden our horizons
and challenge us to think about programming in a way we wouldn’t have
before. I could easily imagine relevant papers dealing with template
metaprogramming in C++, hygiene in OCaml, or domain-specific languages
in Clojure.&lt;/p&gt;

&lt;p&gt;If you think your idea &lt;em&gt;might&lt;/em&gt; be relevant to the workshop, please
don’t hesitate to contact Tom and myself. We’ll gladly give you
an honest assessment of whether your idea would be a good fit. If not,
we’ll do our best to direct you towards an appropriate venue for your
ideas.&lt;/p&gt;

&lt;h4 id=&quot;who-should-submit&quot;&gt;Who should submit?&lt;/h4&gt;

&lt;p&gt;Traditionally, submissions to Scheme Workshop come from those within
or adjacent to academia. However, this is &lt;strong&gt;not&lt;/strong&gt; a requirement. We
welcome submissions from everyone who thinks they have something
thoughtful to say to the Scheme community. This year, I want to
specifically encourage submissions from:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Undergraduate or graduate students who are looking for practice
writing papers on their own. It can be a challenge to develop your
own sense of research style. Scheme Workshop is a great place to get
feedback on your work in a low-stakes environment. Rather than judge
the quality of your work against a high technical bar, we want to
help build your ideas and presentation so that you can be proud of
the way you’re articulating them.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;People within the tech industry who have never written an academic
paper before. Scheme Workshop leans a bit more academic than
conferences such as RacketCon and StrangeLoop. However, this doesn’t
mean we don’t value ideas from industry. If you’re in industry and
would like to write a paper but aren’t sure how, please reach out to
me: I’m happy to Skype with you and speak frankly about how the
process works.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Seasoned Scheme wizards. Scheme Workshop has a long history of
insightful talks from key contributors to the Scheme community. These
community members shape our vision, and guide newcomers (such as
myself!) by helping us understand the key principles that embody the
Scheme community.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;some-random-scheme-workshop-papers-i-liked&quot;&gt;Some random Scheme Workshop papers I liked&lt;/h4&gt;

&lt;p&gt;There’s truly been some amazing work at Scheme Workshop over the
years.  I can’t hope to summarize it all here. Instead, I picked a
random collection of papers to help you get an idea of the workshop’s
direction.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://schemeworkshop.org/2006/15-barzilay.pdf&quot;&gt;A Self-Hosting Evaluator using
HOAS&lt;/a&gt;, by Eli
Barzilay. This paper discusses how–when you’re implementing a
Scheme interpreter in Scheme–you can avoid implementing
substitution by reflecting lambdas from the source language into the
metalangauge (which still gives you means of abstracting, e.g.,
control structure). This is a neat idea that is the perfect size for
Scheme Workshop.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://scheme2006.cs.uchicago.edu/03-mccarthy.pdf&quot;&gt;Interaction-Safe State for the
Web&lt;/a&gt; by Jay
McCarthy and Shriram Krishnamurthi. This paper discusses new
linguistic mechanisms for building abstractions for how we
understand navigation within web applications. I think this idea
nicely combines the practice of building web applications correctly
with the linguistic abstraction mechanisms afforded by Scheme.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://users.cs.northwestern.edu/~robby/pubs/papers/scheme2007-wf.pdf&quot;&gt;Well-typed programs can’t be
blamed&lt;/a&gt;
by Philip Wadler and Robby Findler. This paper from 2007 appears to
be an earlier version of the highly influential 2009 ESOP paper of the
same name.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://www.ccs.neu.edu/home/dherman/research/papers/scheme08-stack-marks.pdf&quot;&gt;Implementing Continuations Marks in
JavaScript&lt;/a&gt;
by John Clements, Ayswarya Sundaram, and David Herman. This paper
discusses how continuation marks can be implemented in JavaScript. I
see this as an exciting paper exploring a novel idea in a new space,
and the authors mention some foundational challenges in scaling up
to languages that allow tail calls with conventional “return”-style
semantics.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;https://users.soe.ucsc.edu/~lkuper/papers/lambdae.pdf&quot;&gt;A pattern matcher for miniKanren–or–How to get into trouble with
CPS macros&lt;/a&gt;
by Andy Keep, Michael Adams, Lindsey Kuper, Will Byrd, and Dan
Friedman. This paper reveals an interesting ramification of writing
macros in a CPS-based style alongside conditional macro
expansion. They build a pattern matcher for the miniKanren
programming language, demonstrating the issue along the way. I like
that this paper reveals a foundational problem in macro engineering.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;help-us-build-a-community&quot;&gt;Help us build a community!&lt;/h4&gt;

&lt;p&gt;The goal of Scheme Workshop is to build a community that celebrates
the fun in presenting beautifully minimal ideas. We often masquerade
these ideas as programs. But we’re all bound together by the passion
we share for articulating our ideas in an elegant way. Programming
languages give us the ability to rapidly interact with our ideas,
breaking and rebuilding our realization of those ideas at a pace never
before seen by humanity. Scheme celebrates this opportunity by
allowing us unprecedented flexibility in the way we articulate and
execute these ideas.&lt;/p&gt;

&lt;p&gt;I hope that you share my excitement. If you do, I sincerely hope
you’ll consider submitting a paper to &lt;a href=&quot;https://thomas.gilray.org/scheme-2019/&quot;&gt;the twentieth workshop on
Scheme and Functional
Programming&lt;/a&gt;!&lt;/p&gt;
</description>
        <pubDate>Wed, 10 Apr 2019 00:00:00 -0400</pubDate>
        <link>/research/functional-programming/scheme/2019/04/10/scheme-workshop/</link>
        <guid isPermaLink="true">/research/functional-programming/scheme/2019/04/10/scheme-workshop/</guid>
        
        
        <category>research</category>
        
        <category>functional-programming</category>
        
        <category>scheme</category>
        
      </item>
    
  </channel>
</rss>
