<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://hemann.pl/feed.xml" rel="self" type="application/atom+xml" /><link href="https://hemann.pl/" rel="alternate" type="text/html" /><updated>2026-08-04T02:37:44+00:00</updated><id>https://hemann.pl/feed.xml</id><title type="html">Jason Hemann</title><subtitle>Personal Site.</subtitle><author><name>Jason Hemann</name><email>jason.hemann@shu.edu</email></author><entry><title type="html">Make macOS tel: links open in Google Voice</title><link href="https://hemann.pl/google-voice-tel-handler/" rel="alternate" type="text/html" title="Make macOS tel: links open in Google Voice" /><published>2026-08-03T00:00:00+00:00</published><updated>2026-08-03T00:00:00+00:00</updated><id>https://hemann.pl/google-voice-tel-handler</id><content type="html" xml:base="https://hemann.pl/google-voice-tel-handler/"><![CDATA[<p>All I wanted was to be able to click on a phone number and have it do
something useful. One bald yak later, here we are. A phone number link
is just a URL. It often looks something like <code class="language-plaintext highlighter-rouge">tel:+18005550111</code>. It
would be nice to click on that and have it do something useful. Click
in Google Maps, click in your terminal, whatever.</p>

<p>On macOS, clicking that link does not necessarily mean your browser
gets to decide what happens. The operating system gets the first vote.
And my macOS system is sure eager to send it to FaceTime. Which I
don’t use and is a dead-end on my system.</p>

<p>Here’s how it works. LaunchServices looks for the application
registered as the handler for the <code class="language-plaintext highlighter-rouge">tel:</code> URL scheme, and it sends the
URL there. Meaning if FaceTime is the current default handler, then
clicking a phone number in Google Maps, in Chrome, can still end up in
FaceTime. No amount of poking through Chrome preferences will fix it.
You can see if you try the more general:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>open <span class="s1">'tel:+18005550111'</span>
</code></pre></div></div>

<p>Boom. FaceTime. From macOS.</p>

<p>I wanted all the <code class="language-plaintext highlighter-rouge">tel:</code> links that the system knows how to dispatch to
open my Google Voice account instead. From the browser, from a
terminal, from a document, from whatever you can think of.</p>

<p>That’s the reason for the little helper app:</p>

<p><a href="https://github.com/jasonhemann/google-voice-tel-handler">google-voice-tel-handler</a></p>

<h2 id="what-the-helper-does">What the helper does</h2>

<p>This is an AppleScript applet with an <code class="language-plaintext highlighter-rouge">on open location</code> handler. The
OS can send URL events to an applet, so the script receives the
original <code class="language-plaintext highlighter-rouge">tel:</code> URL, extracts the phone number, and opens the
corresponding Google Voice call URL in the default browser.</p>

<p>The script accepts the common shapes I’ve seen:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tel:+18005550111
tel://+18005550111
tel:800-555-0111
</code></pre></div></div>

<p>It strips the <code class="language-plaintext highlighter-rouge">tel:</code> wrapper, keeps the digits, and opens a Google Voice URL
using the <code class="language-plaintext highlighter-rouge">/u/0</code> account slot:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://voice.google.com/u/0/calls?a=nc,%2B18005550111
</code></pre></div></div>

<p>Your default browser takes it from there.</p>

<h2 id="how-it-works">How it works</h2>

<p>You can see all the source code. It’s not much, and the AppleScript
itself is pretty readable.</p>

<p>There’s a build script that compiles the applet with
<code class="language-plaintext highlighter-rouge">osacompile</code>, then patches the generated <code class="language-plaintext highlighter-rouge">Info.plist</code> so the bundle has a
stable identity and declares the URL scheme:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CFBundleIdentifier = com.jasonhemann.google-voice-tel-handler
CFBundleURLTypes   = tel
</code></pre></div></div>

<p>The tools involved are already on macOS: <code class="language-plaintext highlighter-rouge">osacompile</code>, <code class="language-plaintext highlighter-rouge">PlistBuddy</code>,
and <code class="language-plaintext highlighter-rouge">codesign</code>.</p>]]></content><author><name>Jason Hemann</name><email>jason.hemann@shu.edu</email></author><summary type="html"><![CDATA[All I wanted was to be able to click on a phone number and have it do something useful. One bald yak later, here we are. A phone number link is just a URL. It often looks something like tel:+18005550111. It would be nice to click on that and have it do something useful. Click in Google Maps, click in your terminal, whatever.]]></summary></entry><entry><title type="html">Why some reverse functions are slow</title><link href="https://hemann.pl/why-some-reverse-functions-are-slow/" rel="alternate" type="text/html" title="Why some reverse functions are slow" /><published>2026-08-03T00:00:00+00:00</published><updated>2026-08-03T00:00:00+00:00</updated><id>https://hemann.pl/why-some-reverse-functions-are-slow</id><content type="html" xml:base="https://hemann.pl/why-some-reverse-functions-are-slow/"><![CDATA[<p>I overheard two students discussing “the time complexity of reverse,” without
any more concrete referent. This post is a response for those students.</p>

<p>If you ask whether <code class="language-plaintext highlighter-rouge">reverse</code> is fast, the right first response is: which
<code class="language-plaintext highlighter-rouge">reverse</code>?</p>

<p>There is a mathematical function called reverse. It takes a list like
<code class="language-plaintext highlighter-rouge">'(1 2 3)</code> and produces <code class="language-plaintext highlighter-rouge">'(3 2 1)</code>. But there are many algorithms that compute
that function. Some are linear time. Some are quadratic time. The result is the
same; the amount of work can be very different.</p>

<p>Here are two Racket programs that both reverse a list:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">define</span> <span class="p">(</span><span class="nf">rev1</span> <span class="nv">l</span><span class="p">)</span>
  <span class="p">(</span><span class="k">cond</span>
    <span class="p">[(</span><span class="nf">empty?</span> <span class="nv">l</span><span class="p">)</span> <span class="o">'</span><span class="p">()]</span>
    <span class="p">[(</span><span class="nf">cons?</span> <span class="nv">l</span><span class="p">)</span>
     <span class="p">(</span><span class="nb">append</span> <span class="p">(</span><span class="nf">rev1</span> <span class="p">(</span><span class="nf">rest</span> <span class="nv">l</span><span class="p">))</span>
             <span class="p">(</span><span class="nb">list</span> <span class="p">(</span><span class="nf">first</span> <span class="nv">l</span><span class="p">)))]))</span>

<span class="p">(</span><span class="k">define</span> <span class="p">(</span><span class="nf">rev2</span> <span class="nv">l</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">rev2-help</span> <span class="nv">l</span> <span class="o">'</span><span class="p">()))</span>

<span class="p">(</span><span class="k">define</span> <span class="p">(</span><span class="nf">rev2-help</span> <span class="nv">l</span> <span class="nv">acc</span><span class="p">)</span>
  <span class="p">(</span><span class="k">cond</span>
    <span class="p">[(</span><span class="nf">empty?</span> <span class="nv">l</span><span class="p">)</span> <span class="nv">acc</span><span class="p">]</span>
    <span class="p">[(</span><span class="nf">cons?</span> <span class="nv">l</span><span class="p">)</span>
     <span class="p">(</span><span class="nf">rev2-help</span> <span class="p">(</span><span class="nf">rest</span> <span class="nv">l</span><span class="p">)</span>
                <span class="p">(</span><span class="nb">cons</span> <span class="p">(</span><span class="nf">first</span> <span class="nv">l</span><span class="p">)</span> <span class="nv">acc</span><span class="p">))]))</span>
</code></pre></div></div>

<p>They compute the same answers:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">&gt;</span> <span class="p">(</span><span class="nf">rev1</span> <span class="o">'</span><span class="p">(</span><span class="nf">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">4</span><span class="p">))</span>
<span class="o">'</span><span class="p">(</span><span class="nf">4</span> <span class="mi">3</span> <span class="mi">2</span> <span class="mi">1</span><span class="p">)</span>

<span class="nv">&gt;</span> <span class="p">(</span><span class="nf">rev2</span> <span class="o">'</span><span class="p">(</span><span class="nf">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">4</span><span class="p">))</span>
<span class="o">'</span><span class="p">(</span><span class="nf">4</span> <span class="mi">3</span> <span class="mi">2</span> <span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>

<p>But <code class="language-plaintext highlighter-rouge">rev1</code> is slower for large lists. The reason is not mysterious once we look
at what each step is forced to do.</p>

<p>Throughout, the complexity measure is time as a function of the length of the
input list. When we say <code class="language-plaintext highlighter-rouge">O(n)</code> or <code class="language-plaintext highlighter-rouge">O(n^2)</code>, <code class="language-plaintext highlighter-rouge">n</code> is the number of elements in the
list being reversed.</p>

<h2 id="lists-are-one-way">Lists Are One-Way</h2>

<p>A Racket list is built out of pairs. Each pair points at the next part of the
list. That makes some operations cheap:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">first</span> <span class="o">'</span><span class="p">(</span><span class="nf">1</span> <span class="mi">2</span> <span class="mi">3</span><span class="p">))</span> <span class="c1">; 1</span>
<span class="p">(</span><span class="nf">rest</span>  <span class="o">'</span><span class="p">(</span><span class="nf">1</span> <span class="mi">2</span> <span class="mi">3</span><span class="p">))</span> <span class="c1">; '(2 3)</span>
<span class="p">(</span><span class="nb">cons</span> <span class="mi">0</span> <span class="o">'</span><span class="p">(</span><span class="nf">1</span> <span class="mi">2</span> <span class="mi">3</span><span class="p">))</span> <span class="c1">; '(0 1 2 3)</span>
</code></pre></div></div>

<p>Each of those operations can be treated as constant time for this discussion.
They look at, or add, the front of the list.</p>

<p>But <code class="language-plaintext highlighter-rouge">append</code> is different. To append one list onto another, Racket has to walk
down the first list. For example:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">append</span> <span class="o">'</span><span class="p">(</span><span class="nf">1</span> <span class="mi">2</span> <span class="mi">3</span><span class="p">)</span> <span class="o">'</span><span class="p">(</span><span class="nf">4</span> <span class="mi">5</span><span class="p">))</span>
</code></pre></div></div>

<p>The result is <code class="language-plaintext highlighter-rouge">'(1 2 3 4 5)</code>, but getting there requires visiting the elements
of <code class="language-plaintext highlighter-rouge">'(1 2 3)</code>. If the first list has length <code class="language-plaintext highlighter-rouge">m</code>, the append takes time
proportional to <code class="language-plaintext highlighter-rouge">m</code>.</p>

<p>That one fact explains the difference between the two versions of <code class="language-plaintext highlighter-rouge">reverse</code>.</p>

<h2 id="the-direct-version">The Direct Version</h2>

<p>The direct version says:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">define</span> <span class="p">(</span><span class="nf">rev1</span> <span class="nv">l</span><span class="p">)</span>
  <span class="p">(</span><span class="k">cond</span>
    <span class="p">[(</span><span class="nf">empty?</span> <span class="nv">l</span><span class="p">)</span> <span class="o">'</span><span class="p">()]</span>
    <span class="p">[(</span><span class="nf">cons?</span> <span class="nv">l</span><span class="p">)</span>
     <span class="p">(</span><span class="nb">append</span> <span class="p">(</span><span class="nf">rev1</span> <span class="p">(</span><span class="nf">rest</span> <span class="nv">l</span><span class="p">))</span>
             <span class="p">(</span><span class="nb">list</span> <span class="p">(</span><span class="nf">first</span> <span class="nv">l</span><span class="p">)))]))</span>
</code></pre></div></div>

<p>In English:</p>

<ol>
  <li>Reverse the rest of the list.</li>
  <li>Put the first element at the end.</li>
</ol>

<p>For a small list, that is perfectly clear:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">rev1</span> <span class="o">'</span><span class="p">(</span><span class="nf">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">4</span><span class="p">))</span>
<span class="nv">=</span> <span class="p">(</span><span class="nb">append</span> <span class="p">(</span><span class="nf">rev1</span> <span class="o">'</span><span class="p">(</span><span class="nf">2</span> <span class="mi">3</span> <span class="mi">4</span><span class="p">))</span> <span class="o">'</span><span class="p">(</span><span class="nf">1</span><span class="p">))</span>
<span class="nv">=</span> <span class="p">(</span><span class="nb">append</span> <span class="p">(</span><span class="nb">append</span> <span class="p">(</span><span class="nf">rev1</span> <span class="o">'</span><span class="p">(</span><span class="nf">3</span> <span class="mi">4</span><span class="p">))</span> <span class="o">'</span><span class="p">(</span><span class="nf">2</span><span class="p">))</span> <span class="o">'</span><span class="p">(</span><span class="nf">1</span><span class="p">))</span>
<span class="nv">=</span> <span class="p">(</span><span class="nb">append</span> <span class="p">(</span><span class="nb">append</span> <span class="p">(</span><span class="nb">append</span> <span class="p">(</span><span class="nf">rev1</span> <span class="o">'</span><span class="p">(</span><span class="nf">4</span><span class="p">))</span> <span class="o">'</span><span class="p">(</span><span class="nf">3</span><span class="p">))</span> <span class="o">'</span><span class="p">(</span><span class="nf">2</span><span class="p">))</span> <span class="o">'</span><span class="p">(</span><span class="nf">1</span><span class="p">))</span>
<span class="nv">=</span> <span class="o">'</span><span class="p">(</span><span class="nf">4</span> <span class="mi">3</span> <span class="mi">2</span> <span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>

<p>The expensive part is hidden in “put the first element at the end.” Since lists
are easy to add to at the front, but not at the back, <code class="language-plaintext highlighter-rouge">rev1</code> uses <code class="language-plaintext highlighter-rouge">append</code>.</p>

<p>For a list of length 4, the append work has this shape:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>append a list of length 0
append a list of length 1
append a list of length 2
append a list of length 3
</code></pre></div></div>

<p>For a list of length <code class="language-plaintext highlighter-rouge">n</code>, the append work has this shape:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0 + 1 + 2 + ... + (n - 1)
</code></pre></div></div>

<p>That sum is the familiar triangular number:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0 + 1 + 2 + ... + (n - 1) = n(n - 1) / 2
</code></pre></div></div>

<p>The important part is the <code class="language-plaintext highlighter-rouge">n^2</code>. The exact constants do not matter for big-O
analysis, so this version is <code class="language-plaintext highlighter-rouge">O(n^2)</code>.</p>

<p>We can also say this with a recurrence. Let <code class="language-plaintext highlighter-rouge">R(n)</code> be the cost of reversing a
list of length <code class="language-plaintext highlighter-rouge">n</code> with <code class="language-plaintext highlighter-rouge">rev1</code>. Let <code class="language-plaintext highlighter-rouge">A(m)</code> be the cost of appending a first list
of length <code class="language-plaintext highlighter-rouge">m</code>. These costs are still measured in terms of list length: <code class="language-plaintext highlighter-rouge">R</code>
varies with the length of the list being reversed, and <code class="language-plaintext highlighter-rouge">A</code> varies with the
length of the first argument to <code class="language-plaintext highlighter-rouge">append</code>.</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>R(0) = constant
R(n) = R(n - 1) + A(n - 1) + constant
</code></pre></div></div>

<p>Since <code class="language-plaintext highlighter-rouge">A(n - 1)</code> is linear in <code class="language-plaintext highlighter-rouge">n - 1</code>, <code class="language-plaintext highlighter-rouge">R(n)</code> accumulates a linear amount of
append work at each level of recursion. Adding those linear pieces together
gives the quadratic sum above.</p>

<h2 id="the-accumulator-version">The Accumulator Version</h2>

<p>The second version uses a helper function:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">define</span> <span class="p">(</span><span class="nf">rev2</span> <span class="nv">l</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">rev2-help</span> <span class="nv">l</span> <span class="o">'</span><span class="p">()))</span>

<span class="p">(</span><span class="k">define</span> <span class="p">(</span><span class="nf">rev2-help</span> <span class="nv">l</span> <span class="nv">acc</span><span class="p">)</span>
  <span class="p">(</span><span class="k">cond</span>
    <span class="p">[(</span><span class="nf">empty?</span> <span class="nv">l</span><span class="p">)</span> <span class="nv">acc</span><span class="p">]</span>
    <span class="p">[(</span><span class="nf">cons?</span> <span class="nv">l</span><span class="p">)</span>
     <span class="p">(</span><span class="nf">rev2-help</span> <span class="p">(</span><span class="nf">rest</span> <span class="nv">l</span><span class="p">)</span>
                <span class="p">(</span><span class="nb">cons</span> <span class="p">(</span><span class="nf">first</span> <span class="nv">l</span><span class="p">)</span> <span class="nv">acc</span><span class="p">))]))</span>
</code></pre></div></div>

<p>This program carries an accumulator, <code class="language-plaintext highlighter-rouge">acc</code>, that represents the part of the
answer built so far. At each step it removes one element from the front of the
input list and adds that element to the front of the accumulator.</p>

<p>Here is the state of the computation for <code class="language-plaintext highlighter-rouge">'(1 2 3 4)</code>:</p>

<table>
  <thead>
    <tr>
      <th>Remaining input</th>
      <th>Accumulator</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">'(1 2 3 4)</code></td>
      <td><code class="language-plaintext highlighter-rouge">'()</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">'(2 3 4)</code></td>
      <td><code class="language-plaintext highlighter-rouge">'(1)</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">'(3 4)</code></td>
      <td><code class="language-plaintext highlighter-rouge">'(2 1)</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">'(4)</code></td>
      <td><code class="language-plaintext highlighter-rouge">'(3 2 1)</code></td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">'()</code></td>
      <td><code class="language-plaintext highlighter-rouge">'(4 3 2 1)</code></td>
    </tr>
  </tbody>
</table>

<p>When the input is empty, the accumulator is the reversed list.</p>

<p>The key operation is <code class="language-plaintext highlighter-rouge">cons</code>, not <code class="language-plaintext highlighter-rouge">append</code>. Adding one item to the front of a
list is constant time. That means each recursive step does a constant amount of
work, then moves to a list that is one element shorter. The accumulator grows,
but the cost of <code class="language-plaintext highlighter-rouge">cons</code> does not grow with it.</p>

<p>If <code class="language-plaintext highlighter-rouge">H(n)</code> is the cost of <code class="language-plaintext highlighter-rouge">rev2-help</code> on a list of length <code class="language-plaintext highlighter-rouge">n</code>, then:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>H(0) = constant
H(n) = H(n - 1) + constant
</code></pre></div></div>

<p>After <code class="language-plaintext highlighter-rouge">n</code> steps, that is just:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>H(n) = constant * n + constant
</code></pre></div></div>

<p>So <code class="language-plaintext highlighter-rouge">rev2-help</code> is <code class="language-plaintext highlighter-rouge">O(n)</code>, and <code class="language-plaintext highlighter-rouge">rev2</code> is also <code class="language-plaintext highlighter-rouge">O(n)</code>.
Again, this is linear in the length of the original input list.</p>

<h2 id="the-lesson">The Lesson</h2>

<p>It is imprecise to say “the complexity of <code class="language-plaintext highlighter-rouge">reverse</code>” without saying which
algorithm we mean. The function being computed is not the whole story.</p>

<p><code class="language-plaintext highlighter-rouge">rev1</code> and <code class="language-plaintext highlighter-rouge">rev2</code> produce the same lists, but <code class="language-plaintext highlighter-rouge">rev1</code> repeatedly pays for
<code class="language-plaintext highlighter-rouge">append</code>, and those costs add up:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0 + 1 + 2 + ... + (n - 1)
</code></pre></div></div>

<p>That is why <code class="language-plaintext highlighter-rouge">rev1</code> is quadratic.</p>

<p><code class="language-plaintext highlighter-rouge">rev2</code> does one constant-time <code class="language-plaintext highlighter-rouge">cons</code> per input element. That is why <code class="language-plaintext highlighter-rouge">rev2</code> is
linear in the length of the list being reversed.</p>

<p>The built-in <code class="language-plaintext highlighter-rouge">reverse</code> you expect from a language implementation should be the
linear-time kind. But if you write your own, the difference between “put it on
the end” and “carry an accumulator” is the difference between an algorithm that
slows down quadratically and one that scales directly with the size of the list.</p>]]></content><author><name>Jason Hemann</name><email>jason.hemann@shu.edu</email></author><summary type="html"><![CDATA[I overheard two students discussing “the time complexity of reverse,” without any more concrete referent. This post is a response for those students.]]></summary></entry><entry><title type="html">How does an interpreter work?</title><link href="https://hemann.pl/how-does-an-interpreter-work/" rel="alternate" type="text/html" title="How does an interpreter work?" /><published>2026-07-08T00:00:00+00:00</published><updated>2026-07-08T00:00:00+00:00</updated><id>https://hemann.pl/how-does-an-interpreter-work</id><content type="html" xml:base="https://hemann.pl/how-does-an-interpreter-work/"><![CDATA[<p>It sometimes helps to step through a non-trivial example of evaluation in order to
understand how an environment dynamically develops during the evaluation. We will
take this program as our running example:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">i</span><span class="p">)</span>
   <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">j</span><span class="p">)</span>
      <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">j</span><span class="p">)</span>
         <span class="nv">i</span><span class="p">)</span>
       <span class="mi">5</span><span class="p">))</span>
    <span class="mi">6</span><span class="p">))</span>
 <span class="mi">7</span><span class="p">)</span>
</code></pre></div></div>

<p>We will step through the execution of this program, but first let us acquaint
ourselves with what the program actually does.</p>

<h2 id="the-outer-application">The Outer Application</h2>

<p>At the top level, this is an application. It is the application of the operator
expression</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">i</span><span class="p">)</span>
  <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">j</span><span class="p">)</span>
     <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">j</span><span class="p">)</span> <span class="nv">i</span><span class="p">)</span> <span class="mi">5</span><span class="p">))</span>
   <span class="mi">6</span><span class="p">))</span>
</code></pre></div></div>

<p>to the operand <code class="language-plaintext highlighter-rouge">7</code>. In an application form, we call the first expression the
<strong><a href="https://www.youtube.com/watch?v=3RA4MykPm4s">operator</a></strong> and the second
expression the operand. The operator is a lambda expression. If I were unsure of
that, we could write a program over our lambda-calculus datatype:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">define</span> <span class="p">(</span><span class="nf">primary-form</span> <span class="nv">expr</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">match</span> <span class="nv">expr</span>
    <span class="p">[</span><span class="o">`,</span><span class="nv">y</span> <span class="nt">#:when</span> <span class="p">(</span><span class="nb">symbol?</span> <span class="nv">y</span><span class="p">)</span> <span class="ss">'variable</span><span class="p">]</span>
    <span class="p">[</span><span class="o">`</span><span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="o">,</span><span class="nv">x</span><span class="p">)</span> <span class="o">,</span><span class="nv">body</span><span class="p">)</span> <span class="ss">'lambda</span><span class="p">]</span>
    <span class="p">[</span><span class="o">`</span><span class="p">(</span><span class="o">,</span><span class="nv">rator</span> <span class="o">,</span><span class="nv">rand</span><span class="p">)</span> <span class="ss">'application</span><span class="p">]))</span>
</code></pre></div></div>

<p>You can use this to verify the program for yourself. The body of that lambda
expression is also an application:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">j</span><span class="p">)</span>
   <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">j</span><span class="p">)</span>
      <span class="nv">i</span><span class="p">)</span> <span class="c1">; this will be the point we discuss most</span>
    <span class="mi">5</span><span class="p">))</span>
 <span class="mi">6</span><span class="p">)</span>
</code></pre></div></div>

<p>There are three useful things to notice. First, this is again an application of
a lambda whose body is also an application. Second, the ultimate value of this
whole big expression is going to come from the value of <code class="language-plaintext highlighter-rouge">i</code>. Third, <code class="language-plaintext highlighter-rouge">i</code> is a
free variable reference in</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">j</span><span class="p">)</span>
   <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">j</span><span class="p">)</span> <span class="nv">i</span><span class="p">)</span> <span class="mi">5</span><span class="p">))</span>
 <span class="mi">6</span><span class="p">)</span>
</code></pre></div></div>

<p>This latter fact should not be surprising. If <code class="language-plaintext highlighter-rouge">x</code> occurs in the scope of an
expression, such as in <code class="language-plaintext highlighter-rouge">(lambda (x) (lambda (y) x))</code>, then that is a bound
reference to <code class="language-plaintext highlighter-rouge">x</code>, since the variable declaration of <code class="language-plaintext highlighter-rouge">x</code> in the lambda expression
is the referent of that bound variable reference.</p>

<p>If we restrict our focus to the body of that same expression, <code class="language-plaintext highlighter-rouge">(lambda (y) x)</code>,
then there must be a free variable reference to <code class="language-plaintext highlighter-rouge">x</code> in the body. That outer
<code class="language-plaintext highlighter-rouge">(lambda (x) ...)</code> is what will bind that free variable.</p>

<h2 id="environments-remember-context">Environments Remember Context</h2>

<p>We perform evaluation of our programs via structural recursion, the same way we
write most other functions. That means the place where we actually want to get
the value of a variable is when we work our way down to the variable line. For
the program above, that happens when we have worked our way all the way down to
<code class="language-plaintext highlighter-rouge">i</code>.</p>

<p>By then, it is too late to figure out the value of <code class="language-plaintext highlighter-rouge">i</code> all by itself, because we
no longer have the information we need to determine what <code class="language-plaintext highlighter-rouge">i</code> means. Our solution
is to accumulate that information as we recur into the expression, and then look
up the meaning of bound variables in our accumulator when we reach a variable
case.</p>

<p>Since there are potentially scads and scads of bound variables in an expression,
we need to track each one differently. When we see <code class="language-plaintext highlighter-rouge">i</code>, we need to know to look
up <code class="language-plaintext highlighter-rouge">i</code> and not <code class="language-plaintext highlighter-rouge">x</code>. We also need to track not just the name of the variable, but
also its meaning. Our accumulator must therefore track two pieces for each
variable: the name, or formal parameter, of the lambda expression, and the value,
or actual argument, to which that formal parameter corresponds in this context.</p>

<p>When do we finally have both of those pieces? Look at the application line:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">match</span> <span class="nv">expr</span>
  <span class="o">...</span>
  <span class="p">[</span><span class="o">`</span><span class="p">(</span><span class="o">,</span><span class="nv">rator</span> <span class="o">,</span><span class="nv">rand</span><span class="p">)</span> <span class="p">((</span><span class="nf">valof</span> <span class="nv">rator</span> <span class="nv">env</span><span class="p">)</span> <span class="p">(</span><span class="nf">valof</span> <span class="nv">rand</span> <span class="nv">env</span><span class="p">))])</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">rator</code> has to evaluate to a Racket procedure, since we are about to call it
like a procedure of one argument. We are going to call that procedure on the
value of the <code class="language-plaintext highlighter-rouge">rand</code>. The <code class="language-plaintext highlighter-rouge">rator</code> and <code class="language-plaintext highlighter-rouge">rand</code> can both be big honkin’
expressions, but ultimately, when we get values for them and pass the results
back up the recursion, the value of the <code class="language-plaintext highlighter-rouge">rator</code> had better be a procedure. The
value of the <code class="language-plaintext highlighter-rouge">rand</code> can be any old value.</p>

<p>Only after we finish evaluating the two sub-pieces of the <code class="language-plaintext highlighter-rouge">rator</code>/<code class="language-plaintext highlighter-rouge">rand</code> form,
and then do the Racket application, do we have both the formal and actual
parameters at the same time.</p>

<h2 id="lambda-bodies-wait">Lambda Bodies Wait</h2>

<p>Here is a simpler example of something like our interpreter:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">b</span><span class="p">)</span> <span class="p">(</span><span class="k">if</span> <span class="nv">b</span> <span class="mi">5</span> <span class="mi">6</span><span class="p">))</span> <span class="p">(</span><span class="nb">not</span> <span class="nv">false</span><span class="p">))</span>
</code></pre></div></div>

<p>We first evaluate the operator and operand to values: the former to a Racket
procedure and the latter to a Racket boolean. Then we call the Racket procedure
on the Racket boolean. Only after that can we evaluate the body <code class="language-plaintext highlighter-rouge">(if b 5 6)</code>.</p>

<p>That is an important point: we never evaluate the body of a lambda expression
until after we have applied it to a value.</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">define</span> <span class="nv">loop</span>
  <span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">x</span><span class="p">)</span>
    <span class="p">(</span><span class="nf">loop</span> <span class="nv">x</span><span class="p">)))</span>
</code></pre></div></div>

<p>The reason you can get by with writing down a definition like <code class="language-plaintext highlighter-rouge">loop</code> is that we
do not evaluate the body of the expression unless and until we invoke it with an
argument.</p>

<h2 id="extending-the-environment">Extending The Environment</h2>

<p>It is on the lambda line that we actually extend our environment. The right-hand
side of the lambda line is:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">a</span><span class="p">)</span>
  <span class="p">(</span><span class="nf">valof</span> <span class="nv">body</span> <span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">y</span><span class="p">)</span>
                <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">eqv?</span> <span class="nv">x</span> <span class="nv">y</span><span class="p">)</span>
                    <span class="nv">a</span>
                    <span class="p">(</span><span class="nf">env</span> <span class="nv">y</span><span class="p">)))))</span>
</code></pre></div></div>

<p>That is the function we invoke with <code class="language-plaintext highlighter-rouge">true</code> or <code class="language-plaintext highlighter-rouge">7</code> or whatever value we have in
our example. It is not until we invoke that function that we begin to evaluate
the body. As soon as we recur in to evaluate the body, we will no longer have
access to the surrounding <code class="language-plaintext highlighter-rouge">(lambda (x) ...)</code>, because that was the point of
recurring down into the smaller expression.</p>

<p>To keep that information with us as we go, we add it to our accumulator, called
an environment. We are using a functional accumulator; we can just as well look
at our interpreter as a mathematical description of a particular function from
variables to values.</p>

<p>This step, adding to the accumulator, is also called <strong>extending</strong> the function.
If you think of a function as a set of pairs, then we have added one more pair:
the mapping of <code class="language-plaintext highlighter-rouge">(x, a)</code>. Notice also that if there were already a mapping from
<code class="language-plaintext highlighter-rouge">x</code>, we will have locally overwritten it. We call this behavior shadowing, and
the function extension in the lambda line shows how we implement that shadowing.</p>

<h2 id="walking-the-example">Walking The Example</h2>

<p>Now let us evaluate the big expression:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">i</span><span class="p">)</span>
   <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">j</span><span class="p">)</span>
      <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">j</span><span class="p">)</span>
         <span class="nv">i</span><span class="p">)</span>
       <span class="mi">5</span><span class="p">))</span>
    <span class="mi">6</span><span class="p">))</span>
 <span class="mi">7</span><span class="p">)</span>
</code></pre></div></div>

<p>We evaluate the two sub-pieces. The <code class="language-plaintext highlighter-rouge">rator</code> evaluates to a procedure, and the
<code class="language-plaintext highlighter-rouge">rand</code> evaluates to <code class="language-plaintext highlighter-rouge">7</code>. When we do the invocation, we start to evaluate the
body:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">j</span><span class="p">)</span>
   <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">j</span><span class="p">)</span>
      <span class="nv">i</span><span class="p">)</span>
    <span class="mi">5</span><span class="p">))</span>
 <span class="mi">6</span><span class="p">)</span>
</code></pre></div></div>

<p>We do so while keeping track of the association that <code class="language-plaintext highlighter-rouge">i</code> should mean <code class="language-plaintext highlighter-rouge">7</code>. If we
wrote the environment out by hand, it would now look like this:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">y</span><span class="p">)</span>
  <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">eqv?</span> <span class="nv">y</span> <span class="ss">'i</span><span class="p">)</span>
      <span class="mi">7</span>
      <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">y</span><span class="p">)</span> <span class="nv">&lt;bomb&gt;</span><span class="p">)</span>
       <span class="nv">y</span><span class="p">)))</span>
</code></pre></div></div>

<p>So we evaluate that body in this environment. In the same fashion, we evaluate
the two sub-pieces, produce the procedure and the value <code class="language-plaintext highlighter-rouge">6</code>, and then do the
application. That means we evaluate this body:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">j</span><span class="p">)</span>
   <span class="nv">i</span><span class="p">)</span>
 <span class="mi">5</span><span class="p">)</span>
</code></pre></div></div>

<p>with one additional binding, <code class="language-plaintext highlighter-rouge">j</code> to <code class="language-plaintext highlighter-rouge">6</code>. If we wrote the environment out by
hand, it would now look like this:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">y</span><span class="p">)</span>
  <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">eqv?</span> <span class="nv">y</span> <span class="ss">'j</span><span class="p">)</span>
      <span class="mi">6</span>
      <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">y</span><span class="p">)</span>
         <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">eqv?</span> <span class="nv">y</span> <span class="ss">'i</span><span class="p">)</span>
             <span class="mi">7</span>
             <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">y</span><span class="p">)</span> <span class="nv">&lt;bomb&gt;</span><span class="p">)</span>
              <span class="nv">y</span><span class="p">)))</span>
       <span class="nv">y</span><span class="p">)))</span>
</code></pre></div></div>

<p>Each time we extend the environment, we wrap the old one with an <code class="language-plaintext highlighter-rouge">if</code> statement
that first checks for the variable we just added, and otherwise recurs to the
slightly smaller environment.</p>

<p>Doing the same again, we evaluate the two sub-pieces, do the Racket application,
and evaluate the body within the extended environment. In this case, that means
we evaluate <code class="language-plaintext highlighter-rouge">i</code> in the following environment:</p>

<div class="language-racket highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">y</span><span class="p">)</span>
  <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">eqv?</span> <span class="nv">y</span> <span class="ss">'j</span><span class="p">)</span>
      <span class="mi">5</span>
      <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">y</span><span class="p">)</span>
         <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">eqv?</span> <span class="nv">y</span> <span class="ss">'j</span><span class="p">)</span>
             <span class="mi">6</span>
             <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">y</span><span class="p">)</span>
                <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">eqv?</span> <span class="nv">y</span> <span class="ss">'i</span><span class="p">)</span>
                    <span class="mi">7</span>
                    <span class="p">((</span><span class="k">lambda</span> <span class="p">(</span><span class="nf">y</span><span class="p">)</span> <span class="nv">&lt;bomb&gt;</span><span class="p">)</span>
                     <span class="nv">y</span><span class="p">)))</span>
              <span class="nv">y</span><span class="p">)))</span>
       <span class="nv">y</span><span class="p">)))</span>
</code></pre></div></div>

<p>Notice two things here. First, as we focus more tightly on a sub-expression of a
sub-expression of a sub-expression, our environment has grown larger and larger.
There is an inverse relationship between how tightly focused we are on a
sub-expression and how large a nested function our environment has become.</p>

<p>Second, the innermost binding for <code class="language-plaintext highlighter-rouge">j</code> in our original expression, <code class="language-plaintext highlighter-rouge">5</code>, has now
blocked out the ability to look up the other meaning of <code class="language-plaintext highlighter-rouge">j</code>. This is our
implementation of shadowing. Because we accumulate these bindings with the most
recent one in front, we can use the recursion into the program’s structure to
get the shadowing behavior right.</p>

<p>When we finally look up <code class="language-plaintext highlighter-rouge">i</code>, we check that it is not <code class="language-plaintext highlighter-rouge">j</code>, then that it is not
<code class="language-plaintext highlighter-rouge">j</code> again, and then finally that <code class="language-plaintext highlighter-rouge">'i</code> is <code class="language-plaintext highlighter-rouge">'i</code>. Since it is, the lookup returns
<code class="language-plaintext highlighter-rouge">7</code>, and the whole expression evaluates to <code class="language-plaintext highlighter-rouge">7</code>.</p>]]></content><author><name>Jason Hemann</name><email>jason.hemann@shu.edu</email></author><summary type="html"><![CDATA[It sometimes helps to step through a non-trivial example of evaluation in order to understand how an environment dynamically develops during the evaluation. We will take this program as our running example:]]></summary></entry><entry><title type="html">Letter of recommendation (from a professor whose class you took)</title><link href="https://hemann.pl/dwic/" rel="alternate" type="text/html" title="Letter of recommendation (from a professor whose class you took)" /><published>2023-08-11T00:00:00+00:00</published><updated>2023-08-11T00:00:00+00:00</updated><id>https://hemann.pl/dwic</id><content type="html" xml:base="https://hemann.pl/dwic/"><![CDATA[<p>Let’s say you did well in an upper-division class with a professor. You enjoyed the class and also enjoyed learning the material. That might seem like it would make the professor a shoo-in as a good recommender for you for your graduate school application. Here’s why that might not be so! It’s important that someone gives you the full scoop on all this. For instance, if I wrote a student such a letter, I might even be doing them a disservice by taking the slot of someone whose word would go farther.</p>

<p>If you have heard the term “DWIC” before, then you’ll know what I’m about to say. Either way, please do make sure you see <a href="https://koronkevi.ch/posts/applying-to-grad-school.html#:~:text=A%20%22Did%20Well%20In%20Class,ability%20in%20classes%2C%20not%20research">Paulette’s thoughts</a>.The point is that “did well in my class” letters don’t count for much because everyone who submits an application did well in the class that they would have had with their letter writer. Anyone should be able to muster that kind of a letter, and so it doesn’t help distinguish the so-so candidates from the great ones. It’s basically table stakes.</p>

<p>Graduate schools typically want comprehensive letters of recommendation that give detailed, nuanced evaluations of your strengths and potential as a student. A letter that simply states that you did well in class doesn’t give much insight into your intellectual ability, research skills, leadership qualities, or any other relevant attributes that graduate schools are looking for in applicants. Good letters generally come from people who’ve seen you work on more long term projects, in either a small-group reading class, or an independent study or a research project. Sometimes this could be a co-op/internship supervisor, depending upon where you did your co-op/internship. A one-off professor can’t offer that kind of perspective, because they didn’t get a chance to work with you in that manner.</p>

<p>If you already have all that other stuff covered, and just need like a third letter to fill out your set, then that’s probably a better fit! Another important caveat: an un-tenured professor probably has less credibility than a tenured one. When could a non-research letter go further than an ordinary DWIC? When I’ve seen an individualized project or two that you’ve worked on, and we’ve talked together several times about that project. When I’ve reaching out for help in a new course. If I can speak to you as a TA or tutor as well as a student. If I’m writing a letter for a masters program vs a phd, or a local scholarship vs a national one.</p>

<p>Be sure and let me know (1) what specifically you’re hoping for me to speak to, (2) how I can best help fit into your overall letters and application, and (3) tell me what kind of a program is this for. MS CS ? PhD CS? MFA, DDS, or MBA? A scholarship? It helps to know what I’m aiming for.</p>

<p>It will also help if you can provide:</p>

<ul>
  <li>A transcript</li>
  <li>A résumé/vita, with all of your pertinent info in it</li>
  <li>Anything in particular you’d like me to try and emphasize.</li>
  <li>A(nother) link to the scholarship/program information (and if they have multiple, <em>which</em> one you’re applying to!)</li>
  <li>And also tell me about your other letter writers.</li>
</ul>]]></content><author><name>Jason Hemann</name><email>jason.hemann@shu.edu</email></author><summary type="html"><![CDATA[Let’s say you did well in an upper-division class with a professor. You enjoyed the class and also enjoyed learning the material. That might seem like it would make the professor a shoo-in as a good recommender for you for your graduate school application. Here’s why that might not be so! It’s important that someone gives you the full scoop on all this. For instance, if I wrote a student such a letter, I might even be doing them a disservice by taking the slot of someone whose word would go farther.]]></summary></entry><entry><title type="html">Is your shell what you think?</title><link href="https://hemann.pl/shells/" rel="alternate" type="text/html" title="Is your shell what you think?" /><published>2023-03-17T00:00:00+00:00</published><updated>2023-03-17T00:00:00+00:00</updated><id>https://hemann.pl/shells</id><content type="html" xml:base="https://hemann.pl/shells/"><![CDATA[<p>Depending how you installed a new version of <code class="language-plaintext highlighter-rouge">bash</code> on your mac, it
might surprise you to learn which version of bash you’re using. For
instance, if ask for the version of bash at the prompt. Here’s a
reasonable example.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>bash <span class="nt">--version</span> 
GNU bash, version 5.2.15<span class="o">(</span>1<span class="o">)</span><span class="nt">-release</span> <span class="o">(</span>aarch64-apple-darwin21.6.0<span class="o">)</span>
</code></pre></div></div>

<p>Looks good. If, however, we then go and check the BASH_VERSION …</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">echo</span> <span class="nv">$BASH_VERSION</span>
3.2.57<span class="o">(</span>1<span class="o">)</span><span class="nt">-release</span>
</code></pre></div></div>

<p>We get a very different and worse number. What gives? Well, your login
shell is using a different version of bash than is currently front on
your path.</p>

<p><a href="login-shell">This SO thread</a> helpfully describes the problem and the
issue. If you are using the new version of homebrew, then you might
have had to move where you keep the programs brew installs: the new
location is <code class="language-plaintext highlighter-rouge">/opt/homebrew/bin</code>. If that’s the one you want to set as
your login shell, then you’ll have to first add it to the
<code class="language-plaintext highlighter-rouge">/etc/shells</code> file, and then use the following to set it.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chsh -s /opt/homebrew/bin/bash
sudo chsh -s /opt/homebrew/bin/bash
</code></pre></div></div>

<p>(If you failed to add that to your <code class="language-plaintext highlighter-rouge">/etc/shells</code> file, then <code class="language-plaintext highlighter-rouge">chsh</code> will
squawk that this is a non-standard shell.)</p>

<p>But after this, you should be good to go with an up-to-date login shell.</p>]]></content><author><name>Jason Hemann</name><email>jason.hemann@shu.edu</email></author><summary type="html"><![CDATA[Depending how you installed a new version of bash on your mac, it might surprise you to learn which version of bash you’re using. For instance, if ask for the version of bash at the prompt. Here’s a reasonable example.]]></summary></entry><entry><title type="html">Job hunting advice.</title><link href="https://hemann.pl/jobs/" rel="alternate" type="text/html" title="Job hunting advice." /><published>2023-02-21T00:00:00+00:00</published><updated>2023-02-21T00:00:00+00:00</updated><id>https://hemann.pl/jobs</id><content type="html" xml:base="https://hemann.pl/jobs/"><![CDATA[<p>I recently had cause to think about some advice for recent graduates
hunting for jobs. This is probably applicable too if you’re laid off
and need to find a new job. Caveats that this worked for me a dozen
years ago, and it’s tailored to students looking for programmer jobs.</p>

<ol>
  <li>Get a second email address that doesn’t obviously look like a
backup email address. You don’t want job mail spam in your inbox
for the rest of eternity.</li>
  <li>Make job hunting your full-time job until you have one. It’s a
9-5 process. There’s a lead time before you’re going to start
seeing results, and you don’t know how long that is, but don’t
sit and wait for that one org of your dreams to get back to you.</li>
  <li>Start with the “usual suspects” job recruiting sites—Monster,
indeed, etc. Fill out profiles and filters and set yourself up
with a feed for job leads.</li>
  <li>Any place that has an RSS feed, find yourself an RSS reader and
subscribe to them. This can be your work list, and mean there’s
a whole bunch of sites you don’t have to check.</li>
  <li>Work backwards in time, from most recent to more distant
postings.</li>
  <li>Niche technology where you have experience can be a good place
to start, because they probably have trouble recruiting for
that.</li>
  <li>When you find a job you want to apply for, do it from the
company’s intranet if you can.</li>
  <li>Google itself also has job search listings now, and you can use
that too.</li>
  <li>Often times when you’re looking up a job listing, you’ll find
another <em>site</em> on which that job is posted that you hadn’t
looked before. This is how you build breadth to your job search.
Let the job listings lead you to more sites, and the job hunt
sites lead you to more jobs listings.</li>
  <li>Recruiters/headhunters can be useful, get in touch w/them too.</li>
  <li>If you’ve graduated recently enough, the school might still
offer advice on your resume. Some schools have an alumni
network that to tap. The other thing I’ve seen is to update
your LinkedIn profile, see where your colleagues and contacts
are working, and then go to those companies’ websites for
listings.</li>
  <li>In fact, you can also start picking out companies that you’ve
heard of that you wouldn’t mind working for, and apply directly
with them. That’s another way to increase your pool of job
sites.</li>
  <li>Use several common search strings for positions on the search
sites. You know that “software engineer” “programmer” “computer
scientist” “software developer” “platform engineer” can bleed
across one another, but the sites don’t and HR might not
either. If a site only lets you have one active search, then
get another email address and another login to that site, and
have your second search set up that way.</li>
  <li>Make sure your resume is AI/search friendly. Use the key words
and phrases that will get you past the automatic filters and
into the hands of a human being.</li>
  <li>Borrow the address of a friend’s couch. If you’re willing to
relocate, and you have someone in the area, then you can put
that person’s address on the resume making you look like a
local hire. “I’ve been staying with a friend out there while I
.. I just recently moved back to my place…” yadda. IME, by the
time you’re far enough along that you seem like a candidate
worth interviewing in person, then that won’t matter. If it
does.</li>
  <li>As I understand it, in person commuting-to-work jobs are going
to be less competitive than the remote jobs, because a) people
place a premium on the work from home and b) you are already
excluding all the people who aren’t in or willing to be in a
commute distance of that job.</li>
  <li>You can and probably should have multiple versions of your
resume tailored to different kinds of positions. Depending on
what technology they want you to work with and what the role
requires, you’ll emphasize different things in your background.
If you can, make it look like you’re already an expert at doing
the job they want to hire you for.</li>
  <li>Double, triple check your emails and spelling and that you’re
addressing the right company with the right job. If you can,
build yourself a little program that will automate portions of
your cover letter. If you’re building it with PDF, then using
TeX macros <code class="language-plaintext highlighter-rouge">\longname</code> <code class="language-plaintext highlighter-rouge">\shortname</code> <code class="language-plaintext highlighter-rouge">\mediumname</code>
<code class="language-plaintext highlighter-rouge">\specialreason</code> to fill in a cover letter could both save you
time and frustration</li>
  <li>Likewise, before you send something, have a tool read it to
you, out loud. You can listen for mistakes that sound obvious
but are difficult to pick out. You can do this on 2x speed if
you’re quick enough. This isn’t a place to be lazy.</li>
  <li>If you have time, especially if you think you’ll be off for a
while, pull out that side project you’d been working on, and
spend some nights and weekends on that. It’s something new you
can show off, looks good on your GitHub commit history, and
gives you something to talk about at an interview.</li>
  <li>This may be less applicable, but <em>if</em> you’re going to be off
work for a <em>while</em> having a volunteer position doing something
related could be helpful just to keep a blank off your resume.
OSS and side projects are nice too, but that doesn’t fit in a
spot on a resume. Maybe start thinking about this in your
second month off, so that you can <em>have</em> something in hand. A
position that you’ve had for 6 months working one day a week
looks better than 5 months off and then a whole month straight
of volunteering.</li>
</ol>

<p>I know <a href="https://youtu.be/KT4vhl8slbE">it’s tough out there</a>. Most of
that is probably common sense to readers, but I hope there’s something
in there that’s worthwhile.</p>]]></content><author><name>Jason Hemann</name><email>jason.hemann@shu.edu</email></author><summary type="html"><![CDATA[I recently had cause to think about some advice for recent graduates hunting for jobs. This is probably applicable too if you’re laid off and need to find a new job. Caveats that this worked for me a dozen years ago, and it’s tailored to students looking for programmer jobs.]]></summary></entry><entry><title type="html">Easy SFTPeasy</title><link href="https://hemann.pl/self-signed-certificate/" rel="alternate" type="text/html" title="Easy SFTPeasy" /><published>2022-11-10T00:00:00+00:00</published><updated>2022-11-10T00:00:00+00:00</updated><id>https://hemann.pl/self-signed-certificate</id><content type="html" xml:base="https://hemann.pl/self-signed-certificate/"><![CDATA[<p>The powers that be here at SHU make some webspace available to faculty
and staff here for course-related materials. This is a nice convenient
alternative to the LMS system for webhosting, and I wanted to explore
what else we could do with it. My contact at the Teaching Learning
Center on campus set me up with some space and an account. That I can
use as soon as I can log in and get to it. All technology and know-how
around campus seems geared toward a pointy-clicky Windows based mode
of operation.</p>

<p>Easy command line access requires a little bit of study and
configuration.</p>

<p>Firstly, the right tool for the job.</p>

<h2 id="btw-sftp--ftps">BTW, <code class="language-plaintext highlighter-rouge">SFTP</code> =/= <code class="language-plaintext highlighter-rouge">FTPS</code></h2>

<p>If you don’t know, <code class="language-plaintext highlighter-rouge">SFTP</code> and <code class="language-plaintext highlighter-rouge">FTPS</code> are not the same thing. If a
person talks to you about “secure FTP”, stop that person immediately
and make them clarify to you which they mean. It’s possible that they
don’t know either: trust, but verify.</p>

<p>I found the easy way to connect to our server
(<code class="language-plaintext highlighter-rouge">tltc-web1h-prod.shu.edu</code>) was to simply <code class="language-plaintext highlighter-rouge">brew install lftp</code>. Scads
of dependencies I needed to download and update all handled for me;
man alive package managers are great!</p>

<p>But I run into a problem when I actually try to use this to get to my
space now. I can connect, but when I actually try and move around, you
run into the following error.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ lftp -u hemannja,"$PASSWD" ftp://tltc-web1h-prod.shu.edu/hemannja/
cd: Fatal error: Certificate verification: self-signed certificate ...
</code></pre></div></div>

<h2 id="certificates-and-verification">Certificates and verification</h2>

<p>This error message is saying that the server has a self-signed
certificate authority, and so my system rightly doesn’t trust it. If
this were a nefarious actor, well, it wouldn’t make any sense to take
his own word that he’s an honest fella. But I happen to know that I’m
really dealing with the machine I think I am, so I want to, for this
guy only, accept the certificate that it’s providing me.</p>

<p>So I need to <em>get</em> the certificate that this server is presenting me</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ openssl s_client -connect tltc-web1h-prod.shu.edu:21 -starttls ftp
...
---
Server certificate
-----BEGIN CERTIFICATE-----
123...
...
...456789abcdefgihijklm==
-----END CERTIFICATE-----
subject=...
issuer=...
---
</code></pre></div></div>

<p>I needed to save that certificate itself as a certificate file. Just
the certificate, mind you.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cat &gt; ~/tltc_web1h_prod_AES-256.crt
...
</code></pre></div></div>

<p>Once I had that, I needed to add it so that <code class="language-plaintext highlighter-rouge">lftp</code> knew about it.</p>

<p>Luckily this was a <a href="https://stackoverflow.com/a/65760327/4355474">solved
problem</a>. If you want to
add it to your MacOS Keychain, <a href="https://support.apple.com/en-my/guide/keychain-access/kyca2431/mac">they also have a help page for
this</a>.</p>]]></content><author><name>Jason Hemann</name><email>jason.hemann@shu.edu</email></author><summary type="html"><![CDATA[The powers that be here at SHU make some webspace available to faculty and staff here for course-related materials. This is a nice convenient alternative to the LMS system for webhosting, and I wanted to explore what else we could do with it. My contact at the Teaching Learning Center on campus set me up with some space and an account. That I can use as soon as I can log in and get to it. All technology and know-how around campus seems geared toward a pointy-clicky Windows based mode of operation.]]></summary></entry><entry><title type="html">Living off the land.</title><link href="https://hemann.pl/living-off-the-land/" rel="alternate" type="text/html" title="Living off the land." /><published>2022-09-08T00:00:00+00:00</published><updated>2022-09-08T00:00:00+00:00</updated><id>https://hemann.pl/living-off-the-land</id><content type="html" xml:base="https://hemann.pl/living-off-the-land/"><![CDATA[<p>We’re mostly cloud computing infrastructure here at SHU, but we do
have a department server. On which I’m not an admin (and shouldn’t
be!)</p>

<p>For my software engineering class however, students (and I) will just
need access to some software sometimes that isn’t installed. For
instance, the default version of <code class="language-plaintext highlighter-rouge">python</code> is 2.7.</p>

<p>However! <code class="language-plaintext highlighter-rouge">python3</code> is already installed! As <code class="language-plaintext highlighter-rouge">python3</code>. As you’d
expect. To be more specific, version 3.6. So that’ll probably suffice.</p>

<p>However, suppose not. Or, just that we wanted to build python3.10.7
from source.</p>

<h1 id="how-to-install-python-310-on-red-hat-enterprise-linux-server">How to install python 3.10 on Red Hat Enterprise Linux Server</h1>
<p>release 7.9 (Maipo) without root</p>

<p>There were several missing modules that were not installed but
optional, one that the output of a failed <code class="language-plaintext highlighter-rouge">make</code> lists as mandatory,
and one that same failure lists as optional but seemed actually
necessary.</p>

<p>The configuration script says it’ll require a more recent version of
openssl than the one we have installed.</p>

<p>So we go <code class="language-plaintext highlighter-rouge">wget</code> ourselves a tarball of the most recent version of
openssl, and then try and configure <em>it</em>.</p>

<p>Well, the version of perl that we have on our system seems broken or
malconfigured, because perl can’t find some basic comes-out-of-the-box
install packages, e.g. <code class="language-plaintext highlighter-rouge">ExtUtils::MakeMaker</code> and <code class="language-plaintext highlighter-rouge">Test::Harness</code>. And
we don’t have CPAN installed either.</p>

<p>Those modules are supposedly core—but I cannot seem to find them
even though I have the standard perl5 installed.</p>

<p>So, the suggestion was to use something like
<a href="https://perlbrew.pl/">perlbrew</a> to just manage, a la homebrew, to
install a local fresh installation of perl5. <code class="language-plaintext highlighter-rouge">perlbrew</code> is pretty
cool!</p>

<p>Out of the box, that failed. But the instructions suggested running
perlpatch, from the same download, to try and fix perl up before doing
the perlbrew of perl.</p>

<p>However, in order to run <em>that</em> command, we need GNU patch which, you
guessed it, isn’t installed on our machine.</p>

<p>I had to download patch <a href="https://ftp.gnu.org/gnu/patch/">from the GNU site</a></p>

<h1 id="installing-in-userspace">Installing in userspace</h1>

<p>Since we’re having to install all of these in userspace, we’ll need to
have a directory convention for the download and install of all this
software. One of the keys is that most of these packages in their
configure script tell you about either a <code class="language-plaintext highlighter-rouge">PREFIX=</code> or <code class="language-plaintext highlighter-rouge">--prefix=</code>
configuration setting to let you install the software wherever you
want (in your own space ofc).</p>

<p>From there, I had to then perlbrew install-patchperl</p>

<p>From there, I had to install (some) right version of perl 5.16.3 in my case.</p>

<p>From there I could finish installing openssl 1.1 and add that on my
path.</p>

<p>Once I had that I was one step closer to installing python3, because
the next issue was that I do not have libffi installed.</p>

<p>The correct way to solve this problem is to download the release of
libffi, which has the installation script built in, and run that
script.</p>

<p>Okay, now these prerequisites are seemingly installed. Why isn’t the
install script running?</p>

<h1 id="flags-to-the-configure-script">Flags to the configure script</h1>

<p>One of the keys was to read the configuration options for the
configure script. These are also <a href="https://docs.python.org/3/using/configure.html#linker-options">reproduced
online:</a></p>

<p><a href="https://bugs.python.org/msg381577">This</a> gave me the flags and
information for how to solve the missing libssl information.</p>

<p>These both describe the problem with the SSL installation, that may
have been a bug in the install script expecting a different directory
structure for openssl.
<a href="https://github.com/pyenv/pyenv/issues/1183">And</a>
<a href="https://github.com/pyenv/pyenv/issues/1183#issuecomment-605018391">also</a>
<a href="https://bugs.python.org/msg321096">these</a>.</p>

<h2 id="ld_library_path"><code class="language-plaintext highlighter-rouge">LD_LIBRARY_PATH</code></h2>

<p>A little bit of cli-fu is just enough to hang yourself. <a href="http://xahlee.info/UnixResource_dir/_/ldpath.html">Xah
Lee</a> gives a nice
history lesson on some of the ways this can bite you. I may or may not
have needed some settings for this install. But I did avail myself.</p>

<h1 id="scripting-it">Scripting it!</h1>

<p>Now that we have a way to build this, we’d sure like to not have to do
it all over again by hand. The right thing to do here is to script the
install. The expedient thing is diligent notes. We won’t expose <em>all</em>
of it here, but certainly this could be useful to the diligent student
reader.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./configure --prefix=$HOME/python \
  LDFLAGS="-L$SPOT/libffi/lib64/ -L$SPOT/openssl/lib/"
  CPPFLAGS="-I$SPOT/openssl/include/openssl/ -I$SPOT/libffi/include/"
  --with-openssl=$SPOT/openssl/
</code></pre></div></div>

<h1 id="takeaways">Takeaways</h1>

<ol>
  <li>
    <p>Be kind to your sysadmin. Buy that person chocolates and Christmas
cards.</p>
  </li>
  <li>
    <p>Read The Friendly Manual. The information you want is sitting
<em>right</em> there. You can of course</p>
  </li>
  <li>
    <p>Your browser is your friend. There was a time when you had mailing
lists and man pages and you felt good that you did. Now, you also have
the ol’ googler.</p>
  </li>
</ol>]]></content><author><name>Jason Hemann</name><email>jason.hemann@shu.edu</email></author><summary type="html"><![CDATA[We’re mostly cloud computing infrastructure here at SHU, but we do have a department server. On which I’m not an admin (and shouldn’t be!)]]></summary></entry><entry><title type="html">Maybe? Definitely.</title><link href="https://hemann.pl/monads/" rel="alternate" type="text/html" title="Maybe? Definitely." /><published>2022-06-20T00:00:00+00:00</published><updated>2022-06-20T00:00:00+00:00</updated><id>https://hemann.pl/monads</id><content type="html" xml:base="https://hemann.pl/monads/"><![CDATA[<p>Here is a use of Scheme’s findf operator.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; (findf number? '(1 #f 2 dog))
1
</code></pre></div></div>

<p>Findf takes a predicate and a list, and returns the first element of
the list for which that predicate holds true, returning #f in the case
that the predicate holds for no member of the list.</p>

<p>So if we change 1 to one, then we will now get a different answer.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; (findf number? '(one #f 2 dog))
2
</code></pre></div></div>

<p>And if we change 2 to two, we get #f, as now no elements of the list
are numbers.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; (findf number? '(one #f two dog))
#f
</code></pre></div></div>

<p>Lets instead ask a different question of this list: boolean?</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; (findf boolean? '(one #f two dog))
#f
</code></pre></div></div>

<p>Whoa ho ho. What’ve we got /here/?</p>

<p>findf returns the first element of the list for which that predicate
holds. #f is a boolean, so that’s what’s returned. Lo, the confusion
that can result.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; (findf boolean? '(one two dog))
#f
</code></pre></div></div>

<p>Let’s look at the issue a bit more abstractly. The meat of the problem
is that the value we’re using to denote
an “error” (“failure”, “exception”, what have you) is /in/ the set of
things that we could possibly return as /actual/ answers. Some
languages use -1 as an error condition instead. Obviously, that’s no
good as an error value here, either.</p>

<p>There’s not a safe value we can pick, because for whatever value we
pick, it might be someone wants to hunt for precisely that value in
their list. For instance, we might try to patch the problem above,
saying to ourselves “Well, #f is useful. Comes up all the time. I’ll
write my own findf, and pick a different thing.” Heck, we’ll choose
this-obscure-symbol-means-failure-Qx29t7.</p>

<p>And that works great until some dingbat comes along and does the
following</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; (my-findf (lambda (y) (eqv? 'this-obscure-symbol-means-failure-Qx29t7 y))
           '(a b c this-obscure-symbol-means-failure-Qx29t7))
this-obscure-symbol-means-failure-Qx29t7
</code></pre></div></div>

<p>But as it turns out, that might not be such a dingbat thing to do,
after all. All the time, we write code that generates code. Someone
who’s generating Scheme code might very well have reason to hunt for
that symbol in a list.</p>

<p>Anyhow. What’s clear is that the above suggestion is just sort of a
patch. These sorts of things come up all the time. We report #f, -1,
Error 404, etc., etc. It seems like there ought to be a unified
approach to handling this sort of problem, and one in which we don’t
have to kludge together some sort of an error code for each distinct
case.</p>

<p>The maybe monad gives us the power to do both of those. It provides a
generic way to handle and propogate failure, and, by virtue of being
general, it means there’s no ad-hoc solution to the value that denotes
an error.</p>

<p>We’ve got return and maybe, those new relatives of eta and * that we
introduced. And we’ve also got fail, which is our way of signaling a
failure.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(define return-maybe
  (lambda (a) `(Just ,a)))
 
(define bind-maybe
  (lambda (ma f)
    (cond
      [(eq? (car ma) 'Just) (f (cadr ma))]
      [(eq? (car ma) 'Nothing) '(Nothing)])))
 
(define fail
  (lambda ()
    '(Nothing)))
</code></pre></div></div>

<p>return is just another name for eta (or unit). More on that in a sec, but a quick
reminder.</p>

<p>There’s lots of monads, and they all have the same type signatures for
the return and bind, and they all have to obey those monadic
laws. We’re gonna walk though, at a type level, what return and bind
/are/, how those things relate to eta and *, why their essence and
behavior makes sense, and then look at how the actual implementations
of return-maybe and bind-maybe make sense.</p>

<p>Whew. That’s a tall order. Well, let’s get to it.</p>

<p>As we were. return is just another name for eta.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>return : alpha -&gt; Malpha
</code></pre></div></div>

<p>The job of return/eta is to take a “pure” value – that is, a value
from the regular land of computation, and wrap it up in the
monad (burrito) (or like Just above.)</p>

<p>For our maybe monad, there are two classes of things that are monadic values.</p>

<p>1 : (Just <x>), where <x> is any old thing you choose. (Must it be a pure value?)
2 : (Nothing)</x></x></p>

<p>This second one is the value provided by invoking fail. Notice that
because all the pure values are wrapped up in a list with Just at the
front, then this (Nothing) doesn’t have the same problem as we had
before with -1 or #f.</p>

<p>If I want to return #f out of my findf-maybe (which we’ll write in a
second), it’ll come out as (Just #f). If I want to signal something’s
not in there, it’ll come out as (Nothing).  (Of course, that could be #f).</p>

<p>And now, let’s consider that same dingbat from before, trying to be
cute again.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; (findf-maybe (lambda (v) (equal v `(Nothing))) '(-1 #f (Nothing) 404))
(Just (Nothing))
</code></pre></div></div>

<p>Ah-HA! Lookie there. Unlike before with Scheme’s findf, now we can tell
when the failure value is exactly that thing looked up in the list,
vs. when it’s actually returned as a failure value. We’ve got the
problem licked. Well, as soon as we figure out bind, relate it to *,
explain why bind-maybe makes sense as a bind, and use this to
implement findf-maybe.</p>

<ul>
  <li>
    <p>was typed as follows.</p>
  </li>
  <li>
    <p>: (alpha -&gt; Mbeta) -&gt; (Malpha -&gt; Mbeta)</p>
  </li>
</ul>

<p>That is, it takes a function and returns a function. A few months ago
that in and of itself might’ve been mind-blowing, but it’s pretty
old-hat now. BTW, if you need a mundane example, integral is the sort
of thing that takes a function and returns a function.</p>

<p>In the biz, we always associate curried functions to the left. If I
have something that looks like</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>f : int -&gt; (bool -&gt; (string -&gt; (bool -&gt; (string -&gt; int))))
</code></pre></div></div>

<p>those parens start to get a bit annoying there.</p>

<p>So we instead write it as</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>f : int -&gt; bool -&gt; string -&gt; bool -&gt; string -&gt; int
</code></pre></div></div>

<p>but we all know what that means. So you’ll more likely see * typed like</p>

<ul>
  <li>: (alpha -&gt; Mbeta) -&gt; Malpha -&gt; Mbeta</li>
</ul>

<p>That is, it’s gonna be a function that takes an f, then it takes an ma.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(define *
  (lambda (f)
    (lambda (ma) ...)))
</code></pre></div></div>

<p>And does … well, who knows what the /particular/ implementation does
at this point, but it does something like calling the function on that
argument.</p>

<p>A quick digression, seemingly apropos of nothing. Let’s define an
operator curried-app.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(define curried-app
  (lambda (f)
    (lambda (a)
      (f a))))
</code></pre></div></div>

<p>Nothing terribly fancy here.</p>

<p>BUT–imagine a world in which that’s the only way you apply
functions. You don’t get to call them directly on their
arguments. Instead, when you wanna apply a function, you pass it to
curried-app, to which you then pass the argument upon which you wanna
call that function.</p>

<p>There’s not much use to doing such a thing when we do our regular
run-of-the-mill Scheme programming. But when we’re working with
monads, it’s a necessity. By the way, did you notice the type of curried-app?</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curried-app : (alpha -&gt; beta) -&gt; alpha -&gt; beta
</code></pre></div></div>

<p>Remarkably, strikingly, /suspiciously/ similar to the type of *. *
does what curried-app does, except it works over monads. When using
monads, we’ve given up the necessity of doing our own function
applications to arguments. It’s passe. Well, not really that, so much
as we’re modeling effects, and we want to make sure the effects happen
the right way. * (well, really it’ll be bind) is going to make sure
that happens, ‘cause it and it alone is allowed to /do/ the
application of functions to monadic arguments. So if * (bind) is
right, then the whole process is right. We’ve deputized * (bind) as
the function-apper. And because * (bind) has to obey the Monadic Laws
if it’s to be a genuine, bonified, monad. Since we’re using
pre-certified monads, we’re certain that they’re up to snuff, so if we
just use’em correctly * (bind) will make all the applications work
properly.</p>

<p>Alright, I’m done writing bind in parens. Let’s describe bind, so that
we can just get to using it. A couple of things.</p>

<ol>
  <li>Writing code with nested calls to * starts to get uuuugly.</li>
</ol>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>((* (lambda (x)
     ((* (lambda (y)
          ((* (lambda (z) ...))
           arg3)))
      arg2)))
 arg1)
</code></pre></div></div>

<p>The flow of control is going to the right. Programs written this way
end up building these giant rightward dagger shapes.</p>

<ol>
  <li>By doing all of our monadic code with calls to a function-apper
mechanism, it makes sense to think of that part of the program as
doing work in units of function-apping. “Do a *, which then demands
another *, which …”. Why bother to curry *? Nothing’s gonna happen
until we give it both parts, and it’s not really of use to do’em one
at a time.</li>
</ol>

<p>It’d be nice if my code read linearly, down the page, rather than
having to follow it out in that triangle pattern, and if I treated
these applications of function to argument as the real unit of work.</p>

<p>Bind does both of those.</p>

<p>The type of bind is</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bind : (Malpha x (alpha -&gt; Mbeta)) -&gt; Mbeta
</code></pre></div></div>

<p>That is, it takes two arguments at once, the argument and the
function, and it takes’em in that order. Notice, now, if we have some
stuff that’s nested, then the work that we do next, that’s part of the
function body, will be underneath the stuff above. We can read what’s
going to happen in order down the page.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(define bind-maybe
  (lambda (ma f)
    (cond
      [(eq? (car ma) 'Just) (f (cadr ma))]
      [(eq? (car ma) 'Nothing) '(Nothing)])))
</code></pre></div></div>

<p>So here’s our definition of bind-maybe, again. We can see it’s doing
at least part of what we wanted it to do. It takes two arguments, in
the right order. We know that ma is one of the things in my maybe
monad. Which means it’s either a (Just <something>) or (Nothing). In
the first case, it's a real and actual value. In the second, there was
an error/failure/exception/badness up the road. If there was an error,
we can't compute on it, and we wanna propagate that forward. So if we
had an error, we return an error.</something></p>

<p>If instead we had a (Just <something>), a non-error value, well we
wanted to do that application. f takes a pure value. We see that,
here. Look, it's taking the cadr of ma. bind, as we theorized, knows
how to take the ma, unwrap the burrito and get ahold of the a, and
call f on it. Whatever comes out of bind needs to still be in the
monad. Pretend this bind is the last thing we do before we end the
computation. Well, I want to make sure I can tell the difference
between returning (Just (Nothing)) and (Nothing), like that yahoo
tried to pull earlier.</something></p>

<p>f, the function we pass in, the one we’re gonna build, needs to be of
alpha -&gt; Mbeta. That way, the thing we hand back is still safely
nestled in the monad. That’s the reason behind the “monads are
space-suits” metaphor.  You can’t open a space-suit
willy-nilly. You’ve got to do it nestled safely inside a
space-capsule. If you do it outside, or go outside not wearing one,
you’ll die in the cold, cold, blackness of space. Alone. That’s what
happens to you if you try to get at the pure inside the monad when you
aren’t supposed to.</p>

<p>A word about those alphas and betas there. They don’t /have/ to be
distinct types. They can be. But they don’t have to be. I’m gonna put
some !s around the parts that you really wanna pay attention to about
the type of bind.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bind : (!Malpha! x (!alpha! -&gt; Mbeta)) -&gt; Mbeta
</code></pre></div></div>

<p>The point is that the thing f takes as an argument is exacty the same
type as the first argument to bind, except the first argument to bind
has it all wrapped up in the monad (burrito).</p>

<p>So that’s the gist of what maybe is. Let’s real quick write findf-maybe
and, ‘cause findf-maybe doesn’t show off everything we’re gonna wanna
do, we’ll write a somewhat contrived example that’ll show off
bind-maybe, too.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(define findf-maybe
  (lambda (p ls)
    (cond
      ((null? ls) (fail))
      ...)))
</code></pre></div></div>

<p>So far, so good, this makes sense. We’ve been promising that we’ll
return (Nothing) when we can’t findf the thing. Whelp, that’ll do it.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(define findf-maybe
  (lambda (p ls)
    (cond
      ((null? ls) (fail))
      (else (let ((a (car ls)))
              (cond
                ((p a) ...)
                (else ...)))))))
</code></pre></div></div>

<p>So here, we’re just setting up and being a bit fancy. I happen to know
for a fact that we’re going to need a couple of times, potentially,
so I’m let-binding it above. There’s the remaining two cases:
either (p a), or not. We’ll handle’em one at a time.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(define findf-maybe
  (lambda (p ls)
    (cond
      ((null? ls) (fail))
      (else (let ((a (car ls)))
              (cond
                ((p a) (return-maybe a))
                (else ...)))))))
</code></pre></div></div>

<p>We wrap the thing up in the monad. findf-maybe is written to have
return-type Mbeta. Which makes sense, according to our spec. We wanted
it to return the stuff wrapped up, again, so we could tell the
difference. That’s why we put it through return. Final case, the
recursive call. Well, findf-maybe spits back something of Mbeta, which
is what we’re after, so nothing special to do here, just the plain-ol’
regular recursion.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(define findf-maybe
  (lambda (p ls)
    (cond
      ((null? ls) (fail))
      (else (let ((a (car ls)))
              (cond
                ((p a) (return-maybe a))
                (else (findf-maybe p (cdr ls)))))))))
</code></pre></div></div>

<p>Voilà. Go forth and findf to your heart’s content. I promised another
example, this time with bind-maybe. We’re gonna try to write an
operator that’ll take a list of numbers and return the product of
their reciprocals. Why? You caught me, no good reason. But let’s do it
anyway, for sport. Or something.</p>

<p>Now, the thing about reciprocals is that zero doesn’t have
one. Division by zero is undefined. So when we try to do this, we’re
gonna have to be on the lookout for a zero, and if we hit one, we come
back out with (Nothing).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(define prod-recip-maybe
  (lambda (ls)
    ...))
</code></pre></div></div>

<p>We’re just gonna blast right through to the new and interesting bit.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(define prod-recip-maybe
  (lambda (ls)
    (cond
      ((null? ls) (return-maybe 1))
      (else
       (let ((a (car ls)))
         (cond
           ((zero? a) (fail))
           (else ...)))))))
</code></pre></div></div>

<p>So we’ve got a non-zero number in the car. Let’s do the recursion, get
that value, and then use it to return the value we’re really
after. I’m doing the recursion, which means I’m coming back with a
value in the monad. And then I wanna do something with the value of
that recursive call, to get the value of the whole expression. This is
a job for bind-maybe. If this was being done non-monadically, and we
were using curried-app, again, it’d look like</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>((curried-app (lambda (rec) (* a rec)))
 (prod-recip-maybe (cdr ls)))
</code></pre></div></div>

<p>But we’re not, we’re 1. in the monad, and 2. really /done/ with that
curried-app thing. Since we’re in the monad, bind-maybe’s gonna do the
job of pulling the pure out of the monadic value. And we’re gonna make
sure that that function returns a monadic value, ‘cause the next fella
up the line is expecting a value in the monad.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(define prod-recip-maybe
  (lambda (ls)
    (cond
      ((null? ls) (return-maybe 1))
      (else
       (let ((a (car ls)))
         (cond
           ((zero? a) (fail))
           (else
            (bind-maybe
             (prod-recip-maybe (cdr ls))
             (lambda (rec)
               (return-maybe (* (/ 1 a) rec)))))))))))
</code></pre></div></div>

<p>Well done. Buut, that is looking a little long, and is slightly
obscuring. That do syntax we introduced would certainly clean some of
this up.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(define-syntax do
  (syntax-rules (&lt;-)
    ((_ bind e) e)
    ((_ bind (v &lt;- e) e* e** ...)
     (bind e (lambda (v) (do bind e* e** ...))))
    ((_ bind e e* e** ...)
     (bind e (lambda (_) (do bind e* e** ...))))))
</code></pre></div></div>

<p>It’s your standard, run-of-the-mill syntax-rules macro. We take which
bind function it is, and a whole bunch of expressions, and expand out
into nested calls to that bind in the right fashion. For our case,
this yields</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(define prod-recip-maybe
  (lambda (ls)
    (cond
      ((null? ls) (return-maybe 1))
      (else
       (let ((a (car ls)))
         (cond
           ((zero? a) (fail))
           (else
            (do bind-maybe
              (rec &lt;- (prod-recip-maybe (cdr ls)))
              (return-maybe (* (/ 1 a) rec))))))))))
</code></pre></div></div>

<p>And /there/ we go.</p>

<p>Now, Go Eat A Burrito! Maybe While Wearing A Space-Suit!</p>]]></content><author><name>Jason Hemann</name><email>jason.hemann@shu.edu</email></author><summary type="html"><![CDATA[Here is a use of Scheme’s findf operator.]]></summary></entry><entry><title type="html">Resolving emacs load path shadows</title><link href="https://hemann.pl/load-path-shadows/" rel="alternate" type="text/html" title="Resolving emacs load path shadows" /><published>2022-04-24T00:00:00+00:00</published><updated>2022-04-24T00:00:00+00:00</updated><id>https://hemann.pl/load-path-shadows</id><content type="html" xml:base="https://hemann.pl/load-path-shadows/"><![CDATA[<p>I recently experienced some emacs problems suggestive of load path
issues. Executing <code class="language-plaintext highlighter-rouge">M-x list-load-path-shadows</code> gives a nice long list
of shadowed files from load path. I use <code class="language-plaintext highlighter-rouge">straight.el</code> as my emacs
package manager. It’s very convenient for all the reasons that the
<code class="language-plaintext highlighter-rouge">straight.el</code> documentation lays out, but naive usage can lead you to
introducing load-path conflicts. Consider an example like the following:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(straight-use-package 'eri)
(straight-use-package 'agda2-mode)
</code></pre></div></div>

<p>I included both of these in my <code class="language-plaintext highlighter-rouge">.emacs</code> configuration, asking
<code class="language-plaintext highlighter-rouge">straight.el</code> to load, and install if necessary, both of these
packages at start-up. However! It turns out <code class="language-plaintext highlighter-rouge">agda2-mode</code> <em>already</em>
includes <code class="language-plaintext highlighter-rouge">eri</code>! But <code class="language-plaintext highlighter-rouge">straight</code> doesn’t know that. So instead we need
to inform it of that fact.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(straight-use-package '(agda2-mode :includes eri))
</code></pre></div></div>

<p>It turns out that <code class="language-plaintext highlighter-rouge">agda2-mode</code> contains within it a couple of things,
so <code class="language-plaintext highlighter-rouge">straight.el</code> provides some extra syntax for passing a list of
options.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(straight-use-package '(agda2-mode :includes (eri annotation)))
</code></pre></div></div>]]></content><author><name>Jason Hemann</name><email>jason.hemann@shu.edu</email></author><summary type="html"><![CDATA[I recently experienced some emacs problems suggestive of load path issues. Executing M-x list-load-path-shadows gives a nice long list of shadowed files from load path. I use straight.el as my emacs package manager. It’s very convenient for all the reasons that the straight.el documentation lays out, but naive usage can lead you to introducing load-path conflicts. Consider an example like the following:]]></summary></entry></feed>