<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Laurent's personal blog</title>
    <link href="https://laurentrdc.xyz/atom.xml" rel="self" />
    <link href="https://laurentrdc.xyz" />
    <id>https://laurentrdc.xyz/atom.xml</id>
    <author>
        <name>Laurent P. René de Cotret</name>
        
    </author>
    <updated>2025-11-06</updated>
    <entry>
    <title>Generating a client for an API - Servant by construction part 4</title>
    <link href="https://laurentrdc.xyz//posts/servant-by-construction/GeneratingAClient.html" />
    <id>https://laurentrdc.xyz//posts/servant-by-construction/GeneratingAClient.html</id>
    <published>2025-11-06T00:00:00Z</published>
    <updated>2025-11-06</updated>
    <summary type="html"><![CDATA[<p>This file is a Literate Haskell module, so we must import things before we get going:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE DataKinds #-}</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE OverloadedStrings #-}</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE TypeFamilies #-}</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- Suppress some warnings which take away from the beauty</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- of the post</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# OPTIONS_GHC -Wno-missing-signatures #-}</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# OPTIONS_GHC -Wno-missing-exported-signatures #-}</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">GeneratingAClient</span> <span class="kw">where</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">ApiAsType</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    ( (<span class="op">:&gt;</span>),</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>      (<span class="op">:&lt;|&gt;</span>)(<span class="op">..</span>),</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Capture</span>,</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Get</span>,</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Post</span>,</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>      <span class="dt">QueryParam</span>,</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>      <span class="dt">ReqBody</span>,</span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Temperature</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>    )</span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad.IO.Class</span> (liftIO)</span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad.Trans.Reader</span> (<span class="dt">ReaderT</span> (runReaderT), ask)</span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.ByteString</span> (<span class="dt">ByteString</span>)</span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.ByteString.Char8</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">BS</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Data</span> (<span class="dt">Proxy</span> (<span class="dt">Proxy</span>))</span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Function</span> ((&amp;))</span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor</span> ((&lt;&amp;&gt;))</span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.List</span> (intercalate)</span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Time</span> (<span class="dt">Day</span>, fromGregorian)</span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">GHC.TypeLits</span> (symbolVal, <span class="dt">KnownSymbol</span>)</span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Network.HTTP.Client</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">HTTP</span></span>
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">ServingAnApi</span> (<span class="dt">API</span>)</span></code></pre></div>
<hr>
<p>Here we are. This is the moment I have been writing for, the end-game. After the last post, where we learned how to <a href="/posts/servant-by-construction/ServingAnApi.html">serve an API</a> while having the compiler enforce the specs of said API, we are ready to generate client functions to query that same API.</p>
<p>The first time I saw this in action, I felt a combination of confusion and awe. In memory of this moment, I’ll just start by the end. Behold:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>(forecastLastUpdated <span class="op">:&lt;|&gt;</span> forecastAtDate) <span class="op">:&lt;|&gt;</span> (getTemperature <span class="op">:&lt;|&gt;</span> postTemperature) <span class="ot">=</span> client (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> <span class="dt">API</span>)</span></code></pre></div>
<p>where <code>forecastLastUpdated</code>, <code>forecastAtDate</code>, <code>getTemperature</code>, and <code>postTemperature</code> are normal Haskell functions that allow us to interact with any server serving the API whose specification respects <code>API</code>, which, as a reminder, is:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">ForecastAPI</span> <span class="ot">=</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>        <span class="st">&quot;forecast&quot;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>            <span class="op">:&gt;</span> ( <span class="st">&quot;lastupdated&quot;</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">UTCTime</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>            <span class="op">:&lt;|&gt;</span> <span class="dt">Capture</span> <span class="st">&quot;date&quot;</span> <span class="dt">Day</span> <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">Temperature</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>               )</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">WeatherAPI</span> <span class="ot">=</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;weather&quot;</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>        <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>            <span class="op">:&gt;</span> ( <span class="dt">QueryParam</span> <span class="st">&quot;city&quot;</span> <span class="dt">City</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">Temperature</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>            <span class="op">:&lt;|&gt;</span> <span class="dt">Capture</span> <span class="st">&quot;city&quot;</span> <span class="dt">City</span> <span class="op">:&gt;</span> <span class="dt">ReqBody</span> <span class="dt">Temperature</span> <span class="op">:&gt;</span> <span class="dt">Post</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>               )</span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">API</span> <span class="ot">=</span> <span class="dt">ForecastAPI</span> <span class="op">:&lt;|&gt;</span> <span class="dt">WeatherAPI</span></span></code></pre></div>
<ul>
<li>“Big deal bud, ever heard of OpenAPI?”</li>
</ul>
<p>OpenAPI is <em>nice</em>, but, it’s also not enough. It’s hard to encode some invariants in an OpenAPI spec. In the set of languages that have <a href="https://openapi-generator.tech/docs/generators">an OpenAPI generator</a>, the level of type sophistication ranges from “huh, types?” to Haskell. OpenAPI sacrifices some of the possible nuances by being more broadly usable.</p>
<p>So, how does this all work? Let’s find out.</p>
<hr>
<p>What does one need, in order to interact with an HTTP API? It needs to know:</p>
<ul>
<li>What’s the hostname, port number, and possibly path where the server can be accessed;</li>
<li>What the endpoints are;</li>
<li>What <em>shape</em> does the requests and responses have, for a given endpoint.</li>
</ul>
<p>We’ll tackle the first point first. When interacting with the API, some knowledge must come externally. We’ll store this information in its own environment type, <code>ClientEnv</code>:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">ClientEnv</span> <span class="ot">=</span> <span class="dt">ClientEnv</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>               {<span class="ot"> hostName ::</span> <span class="dt">String</span>              <span class="co">-- ^ E.g. http://api.server.com</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>               ,<span class="ot"> portNumber ::</span> <span class="dt">Int</span>               <span class="co">-- ^ E.g. 80</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>               ,<span class="ot"> basePath ::</span> <span class="dt">String</span>              <span class="co">-- ^ E.g. /v1</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>               ,<span class="ot"> networkManager ::</span> <span class="dt">HTTP.Manager</span>  <span class="co">-- ^ To make network calls</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>               }</span></code></pre></div>
<p>To promote re-use, we’ll package this data into a monad type that had <code>ClientEnv</code> as a static environment:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">ClientM</span> a <span class="ot">=</span> <span class="dt">ReaderT</span> <span class="dt">ClientEnv</span> <span class="dt">IO</span> a</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="ot">runClientM ::</span> <span class="dt">ClientEnv</span> <span class="ot">-&gt;</span> <span class="dt">ClientM</span> a <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>runClientM <span class="ot">=</span> <span class="fu">flip</span> runReaderT</span></code></pre></div>
<p>Now, if you recall the previous post in this series, we know what “shape” should the client functions be, and by shape, I mean the types. So, it’s going to be relatively straightward to say that, for example, the <code>forecastLastUpdated</code> client function should look like:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ot">forecastAtDate ::</span> <span class="dt">Day</span> <span class="ot">-&gt;</span> <span class="dt">ClientM</span> <span class="dt">Temperature</span></span></code></pre></div>
<p>But, unlike serving the API, we’d like to also define the <em>logic</em> of the client function. Recall that a client function is basically assembles a request to be sent; we’ll chase that thought. Consider a very simple request type like so:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Req</span> <span class="ot">=</span> <span class="dt">Req</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>         {<span class="ot"> reqBody   ::</span> <span class="dt">Maybe</span> <span class="dt">String</span>       <span class="co">-- ^ Optional body of the request</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>         ,<span class="ot"> reqParams ::</span> [(<span class="dt">String</span>, <span class="dt">String</span>)] <span class="co">-- ^ Key-value pairs of query parameters</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>         ,<span class="ot"> reqVerb   ::</span> <span class="dt">ByteString</span>         <span class="co">-- ^ &quot;GET&quot; or &quot;POST&quot;. If unset, the request is not valid.</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>         ,<span class="ot"> reqPath   ::</span> [<span class="dt">String</span>]           <span class="co">-- ^ Path to the endpoint from the base path</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>				                                   <span class="co">--   of the API, e.g. `[&quot;forecast&quot;, &quot;2025-12-01&quot;, &quot;temperature&quot;]`</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>         }</span></code></pre></div>
<p>Note that I’m being quite sloppy here. For example, we should make <code>reqVerb</code> take a sum type rather than any <code>ByteString</code>, but I’m trying to keep things as simple as possible.</p>
<p>We’ll walk through endpoints and construct client functions that, well, construct <code>Req</code>s. Then, we can combine a <code>Req</code> with the <code>ClientEnv</code> to send a HTTP request. Let’s go!</p>
<hr>
<p>As we have done three times already, we will express the functionality we want to add to the <code>API</code> type with a typeclass:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">HasClient</span> api <span class="kw">where</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Client</span> api</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    clientWithRoute ::</span> <span class="dt">Proxy</span> api <span class="ot">-&gt;</span> <span class="dt">Req</span> <span class="ot">-&gt;</span> <span class="dt">Client</span> api</span></code></pre></div>
<p>Before we start writing instances, we’ll make some helper functions to make it easier to deal with <code>Req</code>. First, the empty request:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ot">emptyReq ::</span> <span class="dt">Req</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>emptyReq <span class="ot">=</span> <span class="dt">Req</span> {reqBody <span class="ot">=</span> <span class="dt">Nothing</span>, reqParams <span class="ot">=</span> [], reqVerb <span class="ot">=</span> <span class="fu">mempty</span>, reqPath <span class="ot">=</span> []}</span></code></pre></div>
<p>We need a way to set the body of the request. Recall that for simplicity, we assume that requests are all plaintext encoded, and so we serialize Haskell datatypes over the wire using the <code>Show</code> typeclass:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ot">setBody ::</span> <span class="dt">Show</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Req</span> <span class="ot">-&gt;</span> <span class="dt">Req</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>setBody body req <span class="ot">=</span> req{reqBody <span class="ot">=</span> <span class="dt">Just</span> (<span class="fu">show</span> body)}</span></code></pre></div>
<p>We also need to be able to set the verb of the request – actually, requests are invalid without a verb! You’ll see later how we enforce that all <code>Req</code>s that get sent off have a valid verb later:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ot">setVerb ::</span> <span class="dt">ByteString</span> <span class="ot">-&gt;</span> <span class="dt">Req</span> <span class="ot">-&gt;</span> <span class="dt">Req</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>setVerb verb req <span class="ot">=</span> req{reqVerb <span class="ot">=</span> verb}</span></code></pre></div>
<p>We also need to add query parameters:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ot">addQueryParam ::</span> <span class="dt">Show</span> a <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Req</span> <span class="ot">-&gt;</span> <span class="dt">Req</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>addQueryParam key val req <span class="ot">=</span> req {reqParams <span class="ot">=</span> reqParams req <span class="op">&lt;&gt;</span> [(key, <span class="fu">show</span> val)]}</span></code></pre></div>
<p>and we need to be able to extend the path of the endpoint to which the <code>Req</code> is sent:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="ot">addToPath ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">Req</span> <span class="ot">-&gt;</span> <span class="dt">Req</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>addToPath segment req <span class="ot">=</span> req{reqPath <span class="ot">=</span> reqPath req <span class="op">&lt;&gt;</span> [segment]}</span></code></pre></div>
<p>Finally, we also need a method for sending the request, and receiving the payload. We’ll re-use a low-level library for this, <code>http-client</code>:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="ot">toRequest ::</span> <span class="dt">Req</span> <span class="ot">-&gt;</span> <span class="dt">ClientEnv</span> <span class="ot">-&gt;</span> <span class="dt">HTTP.Request</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>toRequest (<span class="dt">Req</span> body params verb path) (<span class="dt">ClientEnv</span> hostname portnumber basepath _)</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> HTTP.defaultRequest { HTTP.method <span class="ot">=</span> verb</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>                          , HTTP.host <span class="ot">=</span> BS.pack hostname</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>                          , HTTP.port <span class="ot">=</span> portnumber</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>                          , HTTP.path <span class="ot">=</span> BS.pack <span class="op">$</span> basepath <span class="op">&lt;&gt;</span> intercalate <span class="st">&quot;/&quot;</span> path</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>                          , HTTP.queryString <span class="ot">=</span> BS.pack</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>                                             <span class="op">$</span> intercalate <span class="st">&quot;&amp;&quot;</span> [ key <span class="op">&lt;&gt;</span> <span class="st">&quot;=&quot;</span> <span class="op">&lt;&gt;</span> val</span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>                                                               <span class="op">|</span> (key, val) <span class="ot">&lt;-</span> params</span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a>                                                               ]</span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a>                          , HTTP.requestBody <span class="ot">=</span> <span class="dt">HTTP.RequestBodyBS</span> (<span class="fu">maybe</span> <span class="fu">mempty</span> BS.pack body)</span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a>                          }</span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a><span class="ot">runRequestNoBody ::</span> <span class="dt">Req</span> <span class="ot">-&gt;</span> <span class="dt">ClientM</span> ()</span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a>runRequestNoBody req <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb14-18"><a href="#cb14-18" aria-hidden="true" tabindex="-1"></a>    clientEnv<span class="op">@</span>(<span class="dt">ClientEnv</span> _ _ _ networkManager) <span class="ot">&lt;-</span> ask</span>
<span id="cb14-19"><a href="#cb14-19" aria-hidden="true" tabindex="-1"></a>    liftIO (HTTP.httpNoBody (toRequest req clientEnv) networkManager) <span class="op">&lt;&amp;&gt;</span> HTTP.responseBody</span>
<span id="cb14-20"><a href="#cb14-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-21"><a href="#cb14-21" aria-hidden="true" tabindex="-1"></a><span class="ot">runRequest ::</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">Req</span> <span class="ot">-&gt;</span> <span class="dt">ClientM</span> a</span>
<span id="cb14-22"><a href="#cb14-22" aria-hidden="true" tabindex="-1"></a>runRequest req <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb14-23"><a href="#cb14-23" aria-hidden="true" tabindex="-1"></a>    clientEnv<span class="op">@</span>(<span class="dt">ClientEnv</span> _ _ _ networkManager) <span class="ot">&lt;-</span> ask</span>
<span id="cb14-24"><a href="#cb14-24" aria-hidden="true" tabindex="-1"></a>    liftIO (HTTP.httpLbs (toRequest req clientEnv) networkManager)</span>
<span id="cb14-25"><a href="#cb14-25" aria-hidden="true" tabindex="-1"></a>        <span class="op">&lt;&amp;&gt;</span> HTTP.responseBody</span>
<span id="cb14-26"><a href="#cb14-26" aria-hidden="true" tabindex="-1"></a>        <span class="op">&lt;&amp;&gt;</span> BS.toStrict</span>
<span id="cb14-27"><a href="#cb14-27" aria-hidden="true" tabindex="-1"></a>        <span class="op">&lt;&amp;&gt;</span> BS.unpack</span>
<span id="cb14-28"><a href="#cb14-28" aria-hidden="true" tabindex="-1"></a>        <span class="op">&lt;&amp;&gt;</span> <span class="fu">read</span></span></code></pre></div>
<p>With these helper functions out-of-the-way, we can proceed with the real meat of this post. We start with terminal verbs. Recall that, for simplicity, we assume that all POST responses do not carry a body; hence, the client function must return <code>()</code>:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasClient</span> <span class="dt">Post</span> <span class="kw">where</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Client</span> <span class="dt">Post</span> <span class="ot">=</span> <span class="dt">ClientM</span> ()</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>    clientWithRoute _ req <span class="ot">=</span> runRequestNoBody (req <span class="op">&amp;</span> setVerb <span class="st">&quot;POST&quot;</span>)</span></code></pre></div>
<p>Side note: I love <code>&amp;</code> and <code>&lt;&amp;&gt;</code> and I wish to see it more. Moving on to GET:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">HasClient</span> (<span class="dt">Get</span> a) <span class="kw">where</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Client</span> (<span class="dt">Get</span> a) <span class="ot">=</span> <span class="dt">ClientM</span> a</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>    clientWithRoute _ req <span class="ot">=</span> runRequest (req <span class="op">&amp;</span> setVerb <span class="st">&quot;GET&quot;</span>)</span></code></pre></div>
<p><code>Get</code> is a little more interesting because we have to specify a return type. Given our API specification, the parsing of the response body should never fail due to an unexpected type.</p>
<p>Let’s do <code>ReqBody</code> now. A client function for an endpoint using <code>ReqBody a</code> should <em>supply</em> the request with a body of type <code>a</code>; this means adding an argument to the client function, like we did for server handlers:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Show</span> a <span class="ot">=&gt;</span> <span class="dt">HasClient</span> (<span class="dt">ReqBody</span> a <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Client</span> (<span class="dt">ReqBody</span> a <span class="op">:&gt;</span> sub) <span class="ot">=</span> a <span class="ot">-&gt;</span> <span class="dt">Client</span> sub</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>    clientWithRoute _ req <span class="ot">=</span> <span class="op">...</span></span></code></pre></div>
<p>… wait, what should we write for <code>clientWithRoute</code>? Well, in this instance, <code>clientWithRoute :: Proxy ... -&gt; Req -&gt; Client (ReqBody a :&gt; sub)</code>, which is</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="ot">clientWithRoute ::</span> <span class="dt">Proxy</span> (<span class="dt">ReqBody</span> a <span class="op">:&gt;</span> sub)</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>                <span class="ot">-&gt;</span> <span class="dt">Req</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>                <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">Client</span> sub)</span></code></pre></div>
<p>Since <code>ReqBody</code> never appears at the end of an endpoint definition, we must recur with <code>clientWithRoute</code>. This also requires us to make sure that the sub-API, <code>sub</code>, is an instance of <code>HasClient</code>:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">HasClient</span> sub, <span class="dt">Show</span> a) <span class="ot">=&gt;</span> <span class="dt">HasClient</span> (<span class="dt">ReqBody</span> a <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Client</span> (<span class="dt">ReqBody</span> a <span class="op">:&gt;</span> sub) <span class="ot">=</span> a <span class="ot">-&gt;</span> <span class="dt">Client</span> sub</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>    clientWithRoute _ req body <span class="ot">=</span> clientWithRoute (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> sub) (setBody body req)</span></code></pre></div>
<p>Great! Let’s do <code>QueryParam</code>. Recall that in our implementation, a query parameter is always optional. Recall that in <code>QueryParam name a</code>, <code>name</code> is a type-level string which we can bring to the values world by using <code>symbolVal</code>:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">HasClient</span> sub, <span class="dt">KnownSymbol</span> name, <span class="dt">Show</span> a) <span class="ot">=&gt;</span> <span class="dt">HasClient</span> (<span class="dt">QueryParam</span> name a <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Client</span> (<span class="dt">QueryParam</span> name a <span class="op">:&gt;</span> sub) <span class="ot">=</span> <span class="dt">Maybe</span> a <span class="ot">-&gt;</span> <span class="dt">Client</span> sub</span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>    clientWithRoute _ req param <span class="ot">=</span></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>        clientWithRoute</span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>            (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> sub)</span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>            (addQueryParam</span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>                (symbolVal (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> name))</span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a>                param</span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a>                req</span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a>            )</span></code></pre></div>
<p>After this, a <code>Capture</code> is going to be easy:</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">HasClient</span> sub, <span class="dt">Show</span> a) <span class="ot">=&gt;</span> <span class="dt">HasClient</span> (<span class="dt">Capture</span> name a <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Client</span> (<span class="dt">Capture</span> name a <span class="op">:&gt;</span> sub) <span class="ot">=</span> a <span class="ot">-&gt;</span> <span class="dt">Client</span> sub</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>    clientWithRoute _ req capture <span class="ot">=</span></span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>        clientWithRoute</span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a>            (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> sub)</span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a>            (addToPath (<span class="fu">show</span> capture) req)</span></code></pre></div>
<p>We’re almost done. Path segments only add the the path of the request, but otherwise do not add a parameter to our client function:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">HasClient</span> sub, <span class="dt">KnownSymbol</span> segment) <span class="ot">=&gt;</span> <span class="dt">HasClient</span> (segment <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Client</span> (segment <span class="op">:&gt;</span> sub) <span class="ot">=</span> <span class="dt">Client</span> sub</span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>    clientWithRoute _ req</span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>        <span class="ot">=</span> clientWithRoute</span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>            (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> sub)</span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a>            (addToPath (symbolVal (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> segment)) req)</span></code></pre></div>
<p>Finally, the ever-interesting <code>(:&lt;|&gt;)</code> instance. In this case, no thought is required, since there’s only one thing that will type-check:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">HasClient</span> left, <span class="dt">HasClient</span> right) <span class="ot">=&gt;</span> <span class="dt">HasClient</span> (left <span class="op">:&lt;|&gt;</span> right) <span class="kw">where</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Client</span> (left <span class="op">:&lt;|&gt;</span> right) <span class="ot">=</span> <span class="dt">Client</span> left <span class="op">:&lt;|&gt;</span> <span class="dt">Client</span> right</span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>    clientWithRoute _ req</span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a>        <span class="ot">=</span>    clientWithRoute (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> left) req</span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">:&lt;|&gt;</span> clientWithRoute (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> right) req</span></code></pre></div>
<p>Not that much work! How do we connect <code>HasClient</code> with our first demonstration of the function <code>client</code>? Behold:</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="ot">client ::</span> <span class="dt">HasClient</span> api <span class="ot">=&gt;</span> <span class="dt">Proxy</span> api <span class="ot">-&gt;</span> <span class="dt">Client</span> api</span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>client proxy <span class="ot">=</span> clientWithRoute proxy emptyReq</span></code></pre></div>
<p>In action, here’s how we can fetch the forecasted temperature on Christmas:</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="ot">run ::</span> <span class="dt">IO</span> ()</span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a>run <span class="ot">=</span> <span class="kw">do</span></span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a>    networkManager <span class="ot">&lt;-</span> HTTP.newManager HTTP.defaultManagerSettings</span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> clientEnv <span class="ot">=</span> <span class="dt">ClientEnv</span></span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a>                  { hostName <span class="ot">=</span> <span class="st">&quot;myserver.com&quot;</span></span>
<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a>                  , portNumber <span class="ot">=</span> <span class="dv">80</span></span>
<span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a>                  , basePath <span class="ot">=</span> <span class="st">&quot;/api&quot;</span></span>
<span id="cb25-8"><a href="#cb25-8" aria-hidden="true" tabindex="-1"></a>                  , networkManager <span class="ot">=</span> networkManager</span>
<span id="cb25-9"><a href="#cb25-9" aria-hidden="true" tabindex="-1"></a>                  }</span>
<span id="cb25-10"><a href="#cb25-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-11"><a href="#cb25-11" aria-hidden="true" tabindex="-1"></a>        christmasDay <span class="ot">=</span> fromGregorian <span class="dv">2025</span> <span class="dv">12</span> <span class="dv">25</span></span>
<span id="cb25-12"><a href="#cb25-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-13"><a href="#cb25-13" aria-hidden="true" tabindex="-1"></a>    runClientM clientEnv (forecastAtDate christmasDay) <span class="op">&gt;&gt;=</span> liftIO <span class="op">.</span> <span class="fu">print</span></span></code></pre></div>
<p><code>forecastAtDate</code> is just a regular function, but there’s a lot going on under the hood!</p>
<hr>
<p>Automatically generating client functions for an API is beautiful. It looks like magic, but when we look under the hood, it’s “““just”“” type families, partially-applied functions, <code>Proxy</code>, and recursion.</p>
<p>Unlike the previous posts, the code above is NOT a highly simplified version of what Servant provides for real clients via <a href="https://hackage.haskell.org/package/servant-client"><code class="has-text-link">servant-client</code></a>. The only thing we’re missing here is support for the real Servant combinators (powering authentication, streaming, HTTP headers, etc), and allowing for other base monads than <code>IO</code>. That’s not bad!</p>]]></summary>
</entry>
<entry>
    <title>Serving an API - Servant by construction part 3</title>
    <link href="https://laurentrdc.xyz//posts/servant-by-construction/ServingAnApi.html" />
    <id>https://laurentrdc.xyz//posts/servant-by-construction/ServingAnApi.html</id>
    <published>2025-10-30T00:00:00Z</published>
    <updated>2025-10-30</updated>
    <summary type="html"><![CDATA[<p>In the <a href="/posts/servant-by-construction/TypeSafeLinks.html">previous post</a> in this <a href="/posts/servant-by-construction-introduction.html">series</a>, we derived type-safe links for API endpoints. While this wasn’t a revolutionary use of a computer, it set the stage for better, <em>bolder</em> things. We learned about extending Servant using typeclasses, and the central role of <a href="https://hackage.haskell.org/package/base-4.21.0.0/docs/Data-Proxy.html#t:Proxy"><code class="has-text-link">Proxy</code></a>.</p>
<p>Today, we do some <em>real</em> web development stuff: <del>we’ll go too far building abstractions</del> we’ll serve an API.</p>
<hr>
<p>This file is a Literal Haskell module, so we need to get some imports out-of-the-way.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE DataKinds #-}</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE OverloadedStrings #-}</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE TypeFamilies #-}</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">ServingAnApi</span> <span class="kw">where</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">ApiAsType</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    ( (<span class="op">:&gt;</span>),</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>      (<span class="op">:&lt;|&gt;</span>)(<span class="op">..</span>),</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Capture</span>,</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>      <span class="dt">City</span>,</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Get</span>,</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Post</span>,</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>      <span class="dt">QueryParam</span>,</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>      <span class="dt">ReqBody</span>,</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Temperature</span> (<span class="dt">MkTemperature</span>),</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    )</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Data</span> (<span class="dt">Proxy</span> (..))</span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Kind</span> (<span class="dt">Type</span>)</span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Text</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">Text</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Text.Encoding</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">Text</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.ByteString.Lazy</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">ByteString</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.ByteString.Char8</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">ByteString.Char8</span></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Time</span> (<span class="dt">UTCTime</span>, <span class="dt">Day</span>)</span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Time</span> <span class="kw">qualified</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">GHC.TypeLits</span> (<span class="dt">KnownSymbol</span>, symbolVal)</span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Network.Wai.Internal</span> (<span class="dt">Request</span>(..), <span class="dt">Response</span>(..))</span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Network.Wai</span> (<span class="dt">Application</span>, responseLBS, strictRequestBody)</span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Network.Wai.Handler.Warp</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">Warp</span></span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Network.HTTP.Types</span> <span class="kw">qualified</span> <span class="kw">as</span> <span class="dt">HTTP</span></span></code></pre></div>
<p>So, recall from the first post in this series, that we have an API we have modelled:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">ForecastAPI</span> <span class="ot">=</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>        <span class="st">&quot;forecast&quot;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>            <span class="op">:&gt;</span> ( <span class="st">&quot;lastupdated&quot;</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">UTCTime</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>            <span class="op">:&lt;|&gt;</span> <span class="dt">Capture</span> <span class="st">&quot;date&quot;</span> <span class="dt">Day</span> <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">Temperature</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>               )</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">WeatherAPI</span> <span class="ot">=</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;weather&quot;</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>        <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>            <span class="op">:&gt;</span> ( <span class="dt">QueryParam</span> <span class="st">&quot;city&quot;</span> <span class="dt">City</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">Temperature</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>            <span class="op">:&lt;|&gt;</span> <span class="dt">Capture</span> <span class="st">&quot;city&quot;</span> <span class="dt">City</span> <span class="op">:&gt;</span> <span class="dt">ReqBody</span> <span class="dt">Temperature</span> <span class="op">:&gt;</span> <span class="dt">Post</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>               )</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">API</span> <span class="ot">=</span> <span class="dt">ForecastAPI</span> <span class="op">:&lt;|&gt;</span> <span class="dt">WeatherAPI</span></span></code></pre></div>
<p>This API, represented by the <code>API</code> type, has 4 endpoints, split into two sub-APIs, one for forecasting (<code>ForecastAPI</code>) and one for real-time weather measurements (<code>WeatherAPI</code>). We want to write a server application to serve this API.</p>
<p>Now, life is short, priorities already changed twice this sprint, and I don’t like debugging production issues, so we’ll add one more requirement: we want to enforce, at compile-time, that our server application respects our API specification. Let’s go!</p>
<p>Our API specification has 4 endpoints. So, our server application should be composed of 4 functions somehow; each function is the <em>handler</em> for a request to an endpoint. If you forget the details of our API and label the endpoints <code>a</code>, <code>b</code>, <code>c</code>, and <code>d</code>, we need four handler functions <code>ha</code>, <code>hb</code>, <code>hc</code>, and <code>hd</code> for endpoints <code>a</code>, <code>b</code>, <code>c</code>, and <code>d</code> respectively.</p>
<p>This relationship between an endpoint and its handler function isn’t the kind of loving, nurturing relationship you witness on Love Island: it’s entirely dictated by whatever the endpoint specification says. What I mean is that there’s only one handler function that respects any given endpoint specification. We’ll encode this relationship from endpoint to handler function as a <em>function</em>.</p>
<p>Wait a minute, I hear you say. The endpoint specification is a type, and a handler function also has a type. How can this be encoded in a function? Well, the de-facto standard Haskell compiler, GHC, has a feature called <a href="https://downloads.haskell.org/ghc/9.12.2/docs/users_guide/exts/type_families.html"><em>type families</em></a>, which can be used to model type-level functions. I have written about type families before<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> <a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>; I’ll assume that you have an understanding of how they work.</p>
<p>So, just like in our previous post, we will build up a result type (in this case, the type of a server) by walking over the structure of an API type. As you may remember, case-by-case analysis on types can be represented by a <em>typeclass</em> in Haskell. I posit that the following typeclass does it:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">HasServer</span> a <span class="kw">where</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Server</span> a</span></code></pre></div>
<p>That is, for each component type of our API (like <code>Get</code> and <code>Capture</code>), we will have an associated type <code>Server a</code>, the type of the server for the part of the API which is <code>a</code>. It looks like I’m being loose with language here, but I am not: an endpoint has a handler function, but a whole API has a server. It just so happens that if the API is a single endpoint, then the server is also just a handler function.</p>
<p>As before, we will recursively build the <code>Server</code> type for our <code>API</code> type, <code>Server API</code>, by composing the <code>Server</code> for our components. We start with the base case, the return type of an endpoint which is given by the terminal verbs:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasServer</span> <span class="dt">Post</span> <span class="kw">where</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Server</span> <span class="dt">Post</span> <span class="ot">=</span> <span class="dt">IO</span> ()</span></code></pre></div>
<p>This is pretty straightforward: in our implementation, for simplicity, the <code>Post</code> terminal verb never returns any data. Therefore, the handler function for a <code>Post</code> should return nothing, labeled as <code>()</code>.
Note that we make our server implementation run in the <code>IO</code> monad; this is more realistic, as it allows us to do some side effects like interact with a database.</p>
<p>Let’s move on to <code>Get</code>. The handler function for a <code>Get</code> endpoint returns data:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasServer</span> (<span class="dt">Get</span> a) <span class="kw">where</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Server</span> (<span class="dt">Get</span> a) <span class="ot">=</span> <span class="dt">IO</span> a</span></code></pre></div>
<p>Sike, this won’t compile. Haskell is <em>so</em> flexible that the compiler can’t know if <code>a</code> is a type (which can be returned by a function), or something higher-kinded (which <em>cannot</em> be returned by a function). For example, what if <code>a</code> = <code>Proxy</code>? That’s not a type – <code>Proxy</code> is partially-applied, so-to-speak! Therefore, we must be more specific by saying that <code>a</code> must be a concrete type. Behold:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasServer</span> (<span class="dt">Get</span> (<span class="ot">a ::</span> <span class="dt">Type</span>)) <span class="kw">where</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Server</span> (<span class="dt">Get</span> a) <span class="ot">=</span> <span class="dt">IO</span> a</span></code></pre></div>
<p>I sure hope that’s the last technicality we encounter!</p>
<p>Moving on to other component types, you’ll notice that none can be in the end position of an endpoint. This is important: it means that all further definitions of <code>Server</code> will recur!</p>
<p>Let’s move on to <code>ReqBody</code>:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasServer</span> sub <span class="ot">=&gt;</span> <span class="dt">HasServer</span> (<span class="dt">ReqBody</span> (<span class="ot">a ::</span> <span class="dt">Type</span>) <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Server</span> (<span class="dt">ReqBody</span> a <span class="op">:&gt;</span> sub) <span class="ot">=</span> <span class="op">...</span></span></code></pre></div>
<p>We have to think about this. Clearly, the left hand side must involve <code>a</code> and <code>Server sub</code> somehow.
We compose API components using <code>(:&gt;)</code> or <code>(:&lt;|&gt;)</code>. We composed the implementations of <code>toLink</code> using recursive function calls. How are we supposed to compose the types here? Since the resulting type of <code>Server</code> should be a handler function, we should probably compose <code>Server (ReqBody a)</code> and <code>Server sub</code> such that they form a function. Well, the composition of types into a function, in Haskell, is done with <code>(-&gt;)</code>!</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasServer</span> (<span class="dt">ReqBody</span> (<span class="ot">a ::</span> <span class="dt">Type</span>) <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Server</span> (<span class="dt">ReqBody</span> a <span class="op">:&gt;</span> sub) <span class="ot">=</span> a <span class="ot">-&gt;</span> <span class="dt">Server</span> sub</span></code></pre></div>
<p>This makes intuitive sense: the handler function for an endpoint which has a request body of type <code>a</code>, should take <code>a</code> as an <em>argument</em>. Right on!</p>
<p>We move to <code>QueryParam</code>. Recall that we defined our query parameters to be <em>optional</em>, which means that our handler function must take in <code>Maybe a</code> as an argument, not <code>a</code> directly:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasServer</span> (<span class="dt">QueryParam</span> name (<span class="ot">a ::</span> <span class="dt">Type</span>) <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Server</span> (<span class="dt">QueryParam</span> name a <span class="op">:&gt;</span> sub) <span class="ot">=</span> <span class="dt">Maybe</span> a <span class="ot">-&gt;</span> <span class="dt">Server</span> sub</span></code></pre></div>
<p>Great, I’m getting used to this. Now, let’s do path segments. That’s easy, since they don’t affect the logic of our handler function, only the routing of requests (which we will get to later in this post):</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">KnownSymbol</span> segment <span class="ot">=&gt;</span> <span class="dt">HasServer</span> (segment <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Server</span> (segment <span class="op">:&gt;</span> sub) <span class="ot">=</span> <span class="dt">Server</span> sub</span></code></pre></div>
<p>Now we do <code>Capture</code>. Just like <code>ReqBody</code>, this is required and should be a function argument. Therefore:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasServer</span> (<span class="dt">Capture</span> name (<span class="ot">a ::</span> <span class="dt">Type</span>) <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Server</span> (<span class="dt">Capture</span> name a <span class="op">:&gt;</span> sub) <span class="ot">=</span> a <span class="ot">-&gt;</span> <span class="dt">Server</span> sub</span></code></pre></div>
<p>Finally, we have <code>(:&lt;|&gt;)</code>. This is the composition of two handler functions, or two subservers, for two parts of an API, into a true <em>server</em>. We’ll keep this simple for now, and you’ll see how we use it in practice:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasServer</span> (a <span class="op">:&lt;|&gt;</span> b) <span class="kw">where</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Server</span> (a <span class="op">:&lt;|&gt;</span> b) <span class="ot">=</span> <span class="dt">Server</span> a <span class="op">:&lt;|&gt;</span> <span class="dt">Server</span> b</span></code></pre></div>
<p>We did all this work… can we serve that API yet?! Don’t be so hasty. Look at the scrollbar, we’re barely halfway. We need to deal with one more piece of the puzzle: routing requests to the right handler.</p>
<hr>
<p>To route requests, we need to understand the high-level structure of a server. A web server is a program which looks like <code>Request -&gt; IO Response</code></p>
<p>We re-use the Haskell <a href="https://hackage-content.haskell.org/package/wai-3.2.4">Web Application Interface</a> types <code>Request</code> and <code>Response</code>, like Servant and many other Haskell web frameworks also do. Now, the question is: which handler function gets the <code>Request</code>, and thus provides the <code>Response</code>? We need to introduce a method to say whether a handler function matched a route (and thus should process the request), or if the route does not match, in which case another handler function must be tried. We do so using as sum type:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">RouteResult</span> a</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">Matched</span> a</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">NotMatched</span></span></code></pre></div>
<p>Now, for every part of our API, we want to determine a function of type <code>Request -&gt; IO (RouteResult Response)</code>. We will look through the API for the first handler function which returns a <code>Matched Response</code>!</p>
<p>As we’ve done twice now with <code>HasLink</code> and <code>HasServer</code>, we package the functionality in a class, <code>HasRoute</code>:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">RoutingApplication</span> <span class="ot">=</span> <span class="dt">Request</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> (<span class="dt">RouteResult</span> <span class="dt">Response</span>)</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">HasRoute</span> api <span class="kw">where</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    route ::</span> <span class="dt">Proxy</span> api <span class="ot">-&gt;</span> <span class="dt">Server</span> api <span class="ot">-&gt;</span> <span class="dt">RoutingApplication</span></span></code></pre></div>
<p>Recall that we need to use <code>Proxy</code> here because otherwise the type inference won’t work. Yes, even if <code>Server api</code> appears in the type signature, because <code>Server api</code> is a <em>type function</em> whose result is probably not related directly to <code>api</code>!</p>
<p>The plan is to look at the path of the request, and recursively match its content to find the right part of the API for which to return <code>Matched</code>. As we’ve done twice now, we start with the terminal verbs:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="ot">buildResponse ::</span> <span class="dt">Show</span> a <span class="ot">=&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Response</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>buildResponse <span class="ot">=</span> responseLBS HTTP.status200 <span class="fu">mempty</span> <span class="op">.</span> <span class="dt">ByteString</span><span class="op">.</span>fromStrict <span class="op">.</span> Text.encodeUtf8 <span class="op">.</span> Text.pack <span class="op">.</span> <span class="fu">show</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Show</span> a <span class="ot">=&gt;</span> <span class="dt">HasRoute</span> (<span class="dt">Get</span> (<span class="ot">a ::</span> <span class="dt">Type</span>)) <span class="kw">where</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>    route (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> (<span class="dt">Get</span> a)) (<span class="ot">handler ::</span> <span class="dt">IO</span> a) <span class="ot">=</span> \request <span class="ot">-&gt;</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">if</span> (requestMethod request <span class="op">==</span> <span class="st">&quot;GET&quot;</span> <span class="op">&amp;&amp;</span> <span class="fu">null</span> (pathInfo request))</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>            <span class="kw">then</span> <span class="dt">Matched</span> <span class="op">.</span> buildResponse <span class="op">&lt;$&gt;</span> handler</span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>            <span class="kw">else</span> <span class="fu">pure</span> <span class="dt">NotMatched</span></span></code></pre></div>
<p>Oof. A couple of things to note. The first is that, as you can see by our definition of <code>buildResponse</code>, we are modeling a <em>very simple</em> server: a server that never fails (I wish), and thus always returns HTTP200 status codes if a handler is found. Second, the payload of all responses is serialized from the <code>Show</code> instance. This is all in the name of simplicity. In a subsequent post, I <em>may</em> show you how Servant deals with content types – send me an e-mail if you’d like to read that!</p>
<p>The logic of this instance isn’t particularly complex: if the request is a GET request, and we’ve consumed all of its path (and therefore it is the empty list, hence <code>null</code> returns <code>True</code>), then our handler function has indeed matched this route, and we return the result of <code>action</code> as <code>Matched &lt;the response&gt;</code>. I have annotated <code>handler</code> with the type; recall that <code>Server (Get a) === IO a</code>! Otherwise, this handler is NOT the right handler for this request.</p>
<p>The instance for <code>Post</code> is basically similar, but the response is empty (again, to keep things simple). I’ll stop writing out <code>Proxy</code> everywhere, and replace it by <code>_</code>:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasRoute</span> <span class="dt">Post</span> <span class="kw">where</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>    route _ (<span class="ot">handler ::</span> <span class="dt">IO</span> ()) <span class="ot">=</span> \request <span class="ot">-&gt;</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>        <span class="kw">if</span> (requestMethod request <span class="op">==</span> <span class="st">&quot;POST&quot;</span> <span class="op">&amp;&amp;</span> <span class="fu">null</span> (pathInfo request))</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>            <span class="kw">then</span> <span class="dt">Matched</span> <span class="op">.</span> buildResponse <span class="op">&lt;$&gt;</span> handler</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>            <span class="kw">else</span> <span class="fu">pure</span> <span class="dt">NotMatched</span></span></code></pre></div>
<p>Let’s move on to <code>ReqBody</code>. This is the first case where we will recur:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="ot">readReqBody ::</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">Request</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> a</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>readReqBody req <span class="ot">=</span> <span class="fu">read</span> <span class="op">.</span> Text.unpack <span class="op">.</span> Text.decodeUtf8Lenient <span class="op">.</span> <span class="dt">ByteString</span><span class="op">.</span>toStrict <span class="op">&lt;$&gt;</span> strictRequestBody req</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">Read</span> a, <span class="dt">HasRoute</span> sub) <span class="ot">=&gt;</span> <span class="dt">HasRoute</span> (<span class="dt">ReqBody</span> (<span class="ot">a ::</span> <span class="dt">Type</span>) <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>    route _ handler <span class="ot">=</span> \request <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>        readReqBody request <span class="op">&gt;&gt;=</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>            \body <span class="ot">-&gt;</span> route (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> sub) (handler body) request</span></code></pre></div>
<p>There’s a lot going on here! First, we read the body of the request using <code>readReqBody</code>, assuming it is plaintext and always succeeds (insert sarcastic comment). We then pass the <em>parsed</em> body down the routing tree, where the body is used by the handler. One subtle, but awesome, thing to see here is that <code>handler</code> may be a function with lots of arguments – results of query parameters and capture parameters – so <code>handler body</code> could be a partially-applied function!</p>
<p>Time for <code>QueryParam</code>, which are always optional. Just like <code>ReqBody</code>, we don’t bother parsing the data properly, and use <code>read</code> for simplicity:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="ot">readQueryParam ::</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">HTTP.Query</span> <span class="ot">-&gt;</span> <span class="dt">Maybe</span> a</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>readQueryParam paramName query <span class="ot">=</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> paramNameBytes <span class="ot">=</span> <span class="dt">ByteString</span><span class="op">.</span>Char8.pack paramName</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">in</span> <span class="fu">lookup</span> paramNameBytes query</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>        <span class="op">&gt;&gt;=</span> <span class="fu">fmap</span> (<span class="fu">read</span> <span class="op">.</span> <span class="dt">ByteString</span><span class="op">.</span>Char8.unpack)</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">KnownSymbol</span> name, <span class="dt">Read</span> a, <span class="dt">HasRoute</span> sub) <span class="ot">=&gt;</span> <span class="dt">HasRoute</span> (<span class="dt">QueryParam</span> name (<span class="ot">a ::</span> <span class="dt">Type</span>) <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a>    route _ handler <span class="ot">=</span> \request <span class="ot">-&gt;</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> (<span class="ot">queryParam ::</span> <span class="dt">Maybe</span> a) <span class="ot">=</span> readQueryParam (symbolVal (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> name)) (queryString request)</span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>        <span class="kw">in</span> route (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> sub) (handler queryParam) request</span></code></pre></div>
<p>Recall from the last post, that we can use <code>symbolVal</code> to extract the string associated with a type-level string (in this case, <code>name</code>). That <code>name</code> is used to lookup the value of the appropriate query parameter stored in the <code>HTTP.Query</code>, <em>if</em> it is found. Just like with <code>ReqBody</code>, the parsed value, <code>queryParam</code>, is passed to the handler, which may be a partially-applied function!</p>
<p>Onto path segments. As you can imagine, they contribute to <em>routing</em> but handlers are unmodified. A path segment which matches the begining of the request path will continue to route, while if the path segment doesn’t match, we return <code>NotMatched</code>. The key to recursive behavior here is to remove the prefix of the request path on successful match, such that the next segment only has to match the prefix of the path.</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">KnownSymbol</span> segment, <span class="dt">HasRoute</span> sub) <span class="ot">=&gt;</span> <span class="dt">HasRoute</span> (segment <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>    route _ handler <span class="ot">=</span> \request <span class="ot">-&gt;</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> apiSegment <span class="ot">=</span> Text.pack <span class="op">$</span> symbolVal  (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> segment)</span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>        <span class="kw">in</span> <span class="kw">case</span> pathInfo request <span class="kw">of</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>            [] <span class="ot">-&gt;</span> <span class="fu">pure</span> <span class="dt">NotMatched</span></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>            (nextSegment<span class="op">:</span>rest) <span class="ot">-&gt;</span></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a>                <span class="kw">if</span>  nextSegment <span class="op">==</span> apiSegment</span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">then</span> route (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> sub)</span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a>                           handler</span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a>                           (request{pathInfo <span class="ot">=</span> rest})</span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">else</span> <span class="fu">pure</span> <span class="dt">NotMatched</span></span></code></pre></div>
<p>Now path captures. We’re not going to re-invent the wheel here, using the <code>Read</code> instance on the path, and assuming it always succeeds:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="ot">readCapture ::</span> <span class="dt">Read</span> a <span class="ot">=&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> a</span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>readCapture <span class="ot">=</span> <span class="fu">read</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">Read</span> a, <span class="dt">HasRoute</span> sub) <span class="ot">=&gt;</span> <span class="dt">HasRoute</span> (<span class="dt">Capture</span> name (<span class="ot">a ::</span> <span class="dt">Type</span>) <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>    route _ handler <span class="ot">=</span> \request <span class="ot">-&gt;</span> <span class="kw">case</span> pathInfo request <span class="kw">of</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>        [] <span class="ot">-&gt;</span> <span class="fu">pure</span> <span class="dt">NotMatched</span></span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>        (value<span class="op">:</span>rest) <span class="ot">-&gt;</span></span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>            <span class="kw">let</span> captureParam <span class="ot">=</span> readCapture (Text.unpack value)</span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a>            <span class="kw">in</span> route (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> sub)</span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a>                     (handler captureParam)</span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a>                     (request{pathInfo <span class="ot">=</span> rest})</span></code></pre></div>
<p>Finally, we have <code>(:&lt;|&gt;)</code>. This is relatively straightforward: we try the left branch, and return the result of that handler if it returns <code>Matched</code>. Only if the left branch returns <code>NotMatched</code> do we even try the right branch. There’s one interesting tidbit, though: the type function <code>Server (left :&lt;|&gt; right)</code> is a structure of functions, <code>Server left :&lt;|&gt; Server right</code>. This means that the handler we’re using on either branch is of the correct type, always!</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">HasRoute</span> left, <span class="dt">HasRoute</span> right) <span class="ot">=&gt;</span> <span class="dt">HasRoute</span> (left <span class="op">:&lt;|&gt;</span> right) <span class="kw">where</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>    route _ (leftHandler <span class="op">:&lt;|&gt;</span> rightHandler) <span class="ot">=</span> \request <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>        <span class="kw">let</span> tryLeft  <span class="ot">=</span> route (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> left) leftHandler</span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>            tryRight <span class="ot">=</span> route (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> right) rightHandler</span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a>        leftMatch <span class="ot">&lt;-</span> tryLeft request</span>
<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a>        <span class="kw">case</span> leftMatch <span class="kw">of</span></span>
<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a>            <span class="dt">Matched</span> result <span class="ot">-&gt;</span> <span class="fu">pure</span> <span class="op">$</span> <span class="dt">Matched</span> result</span>
<span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a>            <span class="dt">NotMatched</span> <span class="ot">-&gt;</span> tryRight request</span></code></pre></div>
<p>I’d like you to know that it was very hard to resist refactoring this to use <a href="https://hackage.haskell.org/package/base-4.21.0.0/docs/Control-Applicative.html#t:Alternative"><code class="has-text-link">Alternative</code></a>, but this post is already getting long.</p>
<p>Now we have the appropriate blocks to serve our API. In case none of the routes match, we need to build a HTTP404 response:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="ot">notFound ::</span> <span class="dt">Response</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>notFound <span class="ot">=</span> responseLBS HTTP.status404 <span class="fu">mempty</span> <span class="fu">mempty</span></span></code></pre></div>
<p>and beyond this, we just need to provide the <code>Server api</code> structure to a new function, <code>serve</code>:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="ot">serve ::</span> (<span class="dt">HasServer</span> api, <span class="dt">HasRoute</span> api)</span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>      <span class="ot">=&gt;</span> <span class="dt">Proxy</span> api</span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>      <span class="ot">-&gt;</span> <span class="dt">Server</span> api</span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>      <span class="ot">-&gt;</span> (<span class="dt">Request</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Response</span>)</span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a>serve proxy server <span class="ot">=</span> \request <span class="ot">-&gt;</span> <span class="kw">do</span></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>    result <span class="ot">&lt;-</span> route proxy server request</span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">case</span> result <span class="kw">of</span></span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a>        <span class="dt">Matched</span> response <span class="ot">-&gt;</span> <span class="fu">pure</span> response</span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a>        <span class="dt">NotMatched</span> <span class="ot">-&gt;</span> <span class="fu">pure</span> notFound</span></code></pre></div>
<p>So, what does <code>Server api</code> look like? Well, it’s a structure of handler functions, one for each endpoint. We’ll write them all out with trivial logic:</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- To serve GET /forecast/lastupdated</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="ot">forecastLastUpdated ::</span> <span class="dt">IO</span> <span class="dt">UTCTime</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a>forecastLastUpdated <span class="ot">=</span> Data.Time.getCurrentTime</span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- To serve GET /forecast/&lt;date&gt;/temperature</span></span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a><span class="ot">forecastTemperatureAtDate ::</span> <span class="dt">Day</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Temperature</span></span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a>forecastTemperatureAtDate _ <span class="ot">=</span> <span class="fu">pure</span> <span class="op">$</span> <span class="dt">MkTemperature</span> <span class="dv">0</span></span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- To serve GET /weather/temperature&amp;city=&lt;city&gt;</span></span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a><span class="ot">temperatureAtCity ::</span> <span class="dt">City</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Temperature</span></span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true" tabindex="-1"></a>temperatureAtCity _ <span class="ot">=</span> <span class="fu">pure</span> <span class="op">$</span> <span class="dt">MkTemperature</span> <span class="dv">0</span></span>
<span id="cb24-12"><a href="#cb24-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-13"><a href="#cb24-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- To serve POST /weather/temperature/&lt;city&gt;</span></span>
<span id="cb24-14"><a href="#cb24-14" aria-hidden="true" tabindex="-1"></a><span class="ot">recordTemperatureAtCity ::</span> <span class="dt">City</span> <span class="ot">-&gt;</span> <span class="dt">Temperature</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb24-15"><a href="#cb24-15" aria-hidden="true" tabindex="-1"></a>recordTemperatureAtCity _ _ <span class="ot">=</span> <span class="fu">pure</span> () <span class="co">-- This is technically ACID-compliant</span></span></code></pre></div>
<p>We need to combine these four handlers in the same way that the endpoints are structured:</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="ot">apiServer ::</span> <span class="dt">Server</span> <span class="dt">API</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a>apiServer <span class="ot">=</span></span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> forecastAPI <span class="ot">=</span> forecastLastUpdated <span class="op">:&lt;|&gt;</span> forecastTemperatureAtDate</span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a>        weatherAPI <span class="ot">=</span> temperatureAtCity <span class="op">:&lt;|&gt;</span> recordTemperatureAtCity</span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">in</span> forecastAPI <span class="op">:&lt;|&gt;</span> weatherAPI</span></code></pre></div>
<p>If you try this, you’ll get a compilation error! This <em>actually happened</em> as I was writing this blog post; I forgot that <code>QueryParam</code> in <code>temperatureAtCity</code> is actually optional! The type checker has my back, even when writing blog posts. Instead, I need to write:</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="ot">temperatureAtCityCorrect ::</span> <span class="dt">Maybe</span> <span class="dt">City</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Temperature</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>temperatureAtCityCorrect _ <span class="ot">=</span> <span class="fu">pure</span> <span class="op">$</span> <span class="dt">MkTemperature</span> <span class="dv">0</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a><span class="ot">apiServer ::</span> <span class="dt">Server</span> <span class="dt">API</span></span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a>apiServer <span class="ot">=</span></span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> forecastAPI <span class="ot">=</span> forecastLastUpdated <span class="op">:&lt;|&gt;</span> forecastTemperatureAtDate</span>
<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a>        weatherAPI <span class="ot">=</span> temperatureAtCityCorrect <span class="op">:&lt;|&gt;</span> recordTemperatureAtCity</span>
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">in</span> forecastAPI <span class="op">:&lt;|&gt;</span> weatherAPI</span></code></pre></div>
<p>Now it compiles. Let’s pull things all together:</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="ot">myServer ::</span> <span class="dt">Request</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Response</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a>myServer <span class="ot">=</span> serve (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> <span class="dt">API</span>) apiServer</span></code></pre></div>
<p>Now that we have our server logic, we defer the parsing of requests, networking, and other low-level concerns to a lower-level server runner (in this case, <code>warp</code>). Our executable becomes:</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- We convert our handler function to a WAI application, which is slightly</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- different for better resource management (not applicable here)</span></span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a><span class="ot">toApplication ::</span> (<span class="dt">Request</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">Response</span>) <span class="ot">-&gt;</span> <span class="dt">Application</span></span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a>toApplication handler <span class="ot">=</span> \request respond <span class="ot">-&gt;</span> handler request <span class="op">&gt;&gt;=</span> respond</span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a><span class="ot">runServer ::</span> <span class="dt">IO</span> ()</span>
<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a>runServer <span class="ot">=</span> Warp.run <span class="dv">80</span> (toApplication myServer)</span></code></pre></div>
<hr>
<p>And voilà! We built a real HTTP web application using our simplified, homegrown version of Servant. This web server respects the API specification not out of politeness, but out of coercion by the compiler. Amazing!</p>
<p>The code above is admittedly a highly simplified version of what a production-ready web framework should be. Some of the differences between what I’ve shown you here and the real Servant include:</p>
<ul>
<li>Dealing with more failure modes;</li>
<li>Dealing with content-types. Real Servant API specifications encode the accepted content-types, and automatically parse requests and serializes responses based on the type-level description of content types;</li>
<li>Sublinear routing. Our routing algorithm finds a route in linear time, but the real Servant is a lot more clever;</li>
<li>Support for more sophisticated API components, such as streaming endpoints and authentication;</li>
<li>Running handler functions in monads <em>other</em> than <code>IO</code>. This is a big deal if you have to wrangle side effects related to a database, logging facilities, OpenTelemetry, etc.</li>
</ul>
<p>The next post is the last planned post in this series. It’ll deal with <em>automatic derivation</em> of client functions to query a server. See you soon!</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p><a href="/posts/typesafe-tradingstrats.html">Trading strategies with typed features using Haskell and type families</a><a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p><a href="/posts/HKTGenerics.lhs">Modeling dataframes in Haskell using higher-kinded types</a><a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></summary>
</entry>
<entry>
    <title>Type-safe links - Servant by construction part 2</title>
    <link href="https://laurentrdc.xyz//posts/servant-by-construction/TypeSafeLinks.html" />
    <id>https://laurentrdc.xyz//posts/servant-by-construction/TypeSafeLinks.html</id>
    <published>2025-09-29T00:00:00Z</published>
    <updated>2025-09-30</updated>
    <summary type="html"><![CDATA[<p>Recall <a href="/posts/servant-by-construction/ApiAsType.html">the previous post in this series</a>: we created a bunch of types, such as <code>Get</code>, <code>Capture</code>, and <code>(:&gt;)</code>, to help us represent an API. So far, we can’t do squat with these types, but that changes today. By the end of this post, we’ll be able to do <em>one</em> thing: we’ll determine the string representation of an endpoint type.</p>
<p>I know, this isn’t mindblowing, but it will require the use of a basic technique that most Servant functionality uses: the <code>Proxy</code> type. This tool (and others!) will be used again and again as we re-build more powerful components of Servant.</p>
<hr>
<p>This file is a Literate Haskell module, so we have to get some ceremony out-of-the-way.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE DataKinds #-}</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">TypeSafeLinks</span> <span class="kw">where</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- From the previous post in this series</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">ApiAsType</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    ( (<span class="op">:&gt;</span>),</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Capture</span>,</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>      <span class="dt">City</span>,</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Get</span>,</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Post</span>,</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>      <span class="dt">QueryParam</span>,</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>      <span class="dt">ReqBody</span>,</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>      <span class="dt">Temperature</span>,</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    )</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a><span class="co">-- we&#39;ll need these later on</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.List</span> (intersperse)</span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Proxy</span> (<span class="dt">Proxy</span>(..))</span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Time</span> (<span class="dt">Day</span>)</span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">GHC.TypeLits</span> (<span class="dt">KnownSymbol</span>, symbolVal)</span></code></pre></div>
<p>Here’s what we want to do: given the type associated with an endpoint, we want a string that represents a <a href="https://en.wikipedia.org/w/index.php?title=Uniform_Resource_Identifier&amp;oldid=1278623925">universal resource identifier</a> to this endpoint, in the form of a <em>link</em><a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>.</p>
<p>Simply put, for every <em>segment</em> of an endpoint, we want a piece of string that represents it. For example, the endpoint represented by the type</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">ForecastLastUpdated</span> <span class="ot">=</span> <span class="st">&quot;forecast&quot;</span> <span class="op">:&gt;</span> <span class="st">&quot;lastupdated&quot;</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">UTCTime</span></span></code></pre></div>
<p>should give us the link</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;/forecast/lastupdated&quot;</span></span></code></pre></div>
<p>, while the endpoint represented by the type</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">ForecastTemperature</span> <span class="ot">=</span> <span class="st">&quot;forecast&quot;</span> <span class="op">:&gt;</span> <span class="dt">Capture</span> <span class="st">&quot;date&quot;</span> <span class="dt">Day</span> <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">Temperature</span></span></code></pre></div>
<p>should give us the link</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;/forecast/&lt;date&gt;/temperature&quot;</span></span></code></pre></div>
<p>Recall that the segments <code>"forecast"</code>, <code>"lastupdated"</code>, and <code>"temperature"</code> are <em>type-level strings</em>, or <code>Symbol</code>s. The links, such as <code>"/forecast/lastupdated"</code>, <em>will be represented</em> by term-level strings:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Link</span> <span class="ot">=</span> [<span class="dt">String</span>]</span></code></pre></div>
<hr>
<p>Before we break out the advanced type stuff, let’s build this functionality as if we represented our API not with a type, but with data. We’ll focus on only one of the endpoints, specifically the endpoint given by the type:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">ForecastLastUpdated</span> <span class="ot">=</span> <span class="st">&quot;forecast&quot;</span> <span class="op">:&gt;</span> <span class="st">&quot;lastupdated&quot;</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">UTCTime</span></span></code></pre></div>
<p>Imagine if we instead represented that endpoint using the following construction:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">APIComponent</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">Get</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">Segment</span> <span class="dt">String</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">Join</span> <span class="dt">APIComponent</span> <span class="dt">APIComponent</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="ot">exampleEndpoint ::</span> <span class="dt">APIComponent</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>exampleEndpoint <span class="ot">=</span> <span class="dt">Segment</span> <span class="st">&quot;forecast&quot;</span> <span class="ot">`Join`</span> <span class="dt">Segment</span> <span class="st">&quot;lastupdated&quot;</span> <span class="ot">`Join`</span> <span class="dt">Get</span></span></code></pre></div>
<p>Extracting the link from such a value can be done recursively:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ot">endpointLink ::</span> <span class="dt">APIComponent</span> <span class="ot">-&gt;</span> <span class="dt">Either</span> <span class="dt">String</span> <span class="dt">Link</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>endpointLink <span class="ot">=</span> <span class="fu">fmap</span> (intersperse <span class="st">&quot;/&quot;</span>) <span class="op">.</span> go [root]</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">where</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    root ::</span> <span class="dt">String</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    root <span class="ot">=</span> <span class="st">&quot;/&quot;</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="ot">    go ::</span> <span class="dt">Link</span> <span class="ot">-&gt;</span> <span class="dt">APIComponent</span> <span class="ot">-&gt;</span> <span class="dt">Either</span> <span class="dt">String</span> <span class="dt">Link</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>    go accumulator <span class="dt">Get</span> <span class="ot">=</span> <span class="dt">Right</span> accumulator</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>    go accumulator (<span class="dt">Join</span> (<span class="dt">Segment</span> segment) component) <span class="ot">=</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>        go (accumulator <span class="op">&lt;&gt;</span> [segment]) component</span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- Any other structure is considered a malformed API</span></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>    go _ _ <span class="ot">=</span> <span class="dt">Left</span> <span class="st">&quot;Endpoint structure doesn&#39;t make sense&quot;</span></span></code></pre></div>
<p>(Sidenote: please forgive me for appending to a linked list; I’m trying to keep things as simple as possible.)</p>
<p>The result would be:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a> ghci<span class="op">&gt;</span> endpointLink exampleEndpoint</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;/forecast/lastupdated&quot;</span></span></code></pre></div>
<p>The key concept in <code>endpointLink</code> is that we recursively walk over the parts of the endpoint until we hit a verb, in this case <code>Get</code>, while accumulating parts of the link. When we build this functionality for type-level API definitions, we’ll do something very similar: we’ll walk over all components of the API type with a function, accumulating parts of the link, until we hit a terminal verb.</p>
<p>Note that we had to handle the case of nonsensical API structures at runtime. In this case, the only valid API are those composed of zero or more <code>Segment</code>s ultimately ending in <code>Get</code>, all joined with <code>Join</code>. Any other structure results in an error, represented by <code>Left "..."</code>.</p>
<hr>
<p>Let’s move back to the world of APIs defined as types.</p>
<p>The component of an API type, like <code>Capture</code> or a type-level symbol <code>"forecast"</code>, is associated with zero or more segments. This type-level “case-by-case” is the realm of <strong>typeclasses</strong>. We want to create a typeclass, and apply it recursively over our API type, building from the base link <code>"/"</code> incrementally. Let’s <em>try</em> to create this typeclass:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">HasLink1</span> endpoint <span class="kw">where</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    toLink1 ::</span> <span class="dt">Link</span> <span class="co">-- ^ base link, initially just &quot;/&quot;</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>            <span class="ot">-&gt;</span> <span class="dt">Link</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- Example</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasLink1</span> <span class="st">&quot;forecast&quot;</span> <span class="kw">where</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="ot">    toLink1 ::</span> <span class="dt">Link</span> <span class="ot">-&gt;</span> <span class="dt">Link</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>    toLink1 baselink <span class="ot">=</span> [baselink, <span class="st">&quot;forecast&quot;</span>]</span></code></pre></div>
<p>Unfortunately, this is not going to compile. The problem is that type inference won’t work; given a <code>toLink1</code> in the middle of a Haskell file, how can the compiler know which <code>endpoint</code> type it refers to? It can’t know. We need to inject type information in the signature of <code>toLink1</code>.</p>
<p>How about this?</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">HasLink2</span> endpoint <span class="kw">where</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    toLink2 ::</span> <span class="dt">Link</span> <span class="co">-- ^ base link</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>            <span class="ot">-&gt;</span> endpoint</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>            <span class="ot">-&gt;</span> <span class="dt">Link</span></span></code></pre></div>
<p>This would work, if we could construct a <em>term</em> of type <code>endpoint</code>… which we can’t, since many of our API component types, like <code>Get a</code>, don’t have constructors. The API component types are entirely for type-level computation; we can’t construct values for them by design.</p>
<p>So, how do we inject type information, without an associated value? <strong>Put down that <code>undefined</code></strong> ಠ_ಠ we don’t do that here. Being respectable, modern Haskellers, we’ll reach for <a href="https://hackage.haskell.org/package/base-4.21.0.0/docs/Data-Proxy.html#t:Proxy"><code class="has-text-link">Proxy</code></a>. <code>Proxy</code> is a higher-kinded type that allows us to carry a <em>type witness</em>, without having to construct any values (since the <code>Proxy</code> constructor takes no parameter). It’s defined like so:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Proxy</span> a <span class="ot">=</span> <span class="dt">Proxy</span></span></code></pre></div>
<p>We can now reformulate our class as the final, correct version:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">HasLink</span> endpoint <span class="kw">where</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    toLink ::</span> <span class="dt">Proxy</span> endpoint</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>           <span class="ot">-&gt;</span> <span class="dt">Link</span> <span class="co">-- ^ Base link</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>           <span class="ot">-&gt;</span> <span class="dt">Link</span></span></code></pre></div>
<p>where the use of <code>Proxy</code> will allow the compiler to infer type information.</p>
<p>Now, we need to write typeclass instances of the class <code>HasLink</code> for all of the building blocks that make up our API. The easiest instances of <code>HasLink</code> are for the terminal verbs, as they do not appear in the endpoint link:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasLink</span> (<span class="dt">Get</span> a) <span class="kw">where</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    toLink ::</span> <span class="dt">Proxy</span> (<span class="dt">Get</span> a) <span class="ot">-&gt;</span> <span class="dt">Link</span> <span class="ot">-&gt;</span> <span class="dt">Link</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>    toLink _ baselink <span class="ot">=</span> baselink</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasLink</span> <span class="dt">Post</span> <span class="kw">where</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="ot">    toLink ::</span> <span class="dt">Proxy</span> <span class="dt">Post</span> <span class="ot">-&gt;</span> <span class="dt">Link</span> <span class="ot">-&gt;</span> <span class="dt">Link</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>    toLink _ baselink <span class="ot">=</span> baselink</span></code></pre></div>
<p>There’s something else about the terminal verbs, <code>Get</code> and <code>Post</code>: we expect them at the end of our endpoint. There’s no recursion inside <code>toLink</code> here, because by definition, the description of an endpoint as a type always <strong>ends</strong> in <code>Get</code> or <code>Post</code>. These are the base cases.</p>
<p>On the other hand, query parameters and POST request bodies don’t appear in the endpoint link either, but cannot be placed at the end position of the endpoint definition; they are always contained in a <code>(:&gt;)</code>:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasLink</span> sub <span class="ot">=&gt;</span> <span class="dt">HasLink</span> (<span class="dt">ReqBody</span> b <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    toLink ::</span> <span class="dt">Proxy</span> (<span class="dt">ReqBody</span> b <span class="op">:&gt;</span> sub) <span class="ot">-&gt;</span> <span class="dt">Link</span> <span class="ot">-&gt;</span> <span class="dt">Link</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>    toLink _ <span class="ot">=</span> toLink (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> sub)</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">HasLink</span> sub <span class="ot">=&gt;</span> <span class="dt">HasLink</span> (<span class="dt">QueryParam</span> name a <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a><span class="ot">    toLink ::</span> <span class="dt">Proxy</span> (<span class="dt">QueryParam</span> name a <span class="op">:&gt;</span> sub) <span class="ot">-&gt;</span> <span class="dt">Link</span> <span class="ot">-&gt;</span> <span class="dt">Link</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>    toLink _ <span class="ot">=</span> toLink (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> sub)</span></code></pre></div>
<p>Here, we see something different than for <code>Get</code> and <code>Post</code>: the definition of <code>toLink</code> recurs as it moves along the endpoint type.</p>
<p>Let’s pause here for a second, because there’s something very cool that’s easy to miss: we can control what a valid API looks like by NOT writing instances for <code>HasLink</code>. For example, it doesn’t make sense to create a link to <em>something</em> involving <code>:&lt;|&gt;</code>; for example, <code>left :&lt;|&gt; right</code> is for composing endpoints <code>left</code> and <code>right</code> into an API, but there’s no link that makes sense for <code>left :&lt;|&gt; right</code> itself. Well, if we don’t write an instance <code>HasLink (a :&lt;|&gt; b)</code>, we’ll never be able to construct a link to a malformed endpoint, because <code>toLink</code> won’t compile! We’ve transformed the runtime error (<code>Left "..."</code>) from our function <code>endpointLink</code> above, into a <strong>compile-time</strong> error. How awesome is that?!</p>
<p>Let’s climb down from this apotheosis, as it were, and move to the <code>HasLink</code> instance for the path components of endpoints, for which we’ve been using <code>Symbol</code>. Obviously, the type <code>("some-string" :: Symbol)</code> should result in the link fragment <code>("some-string" :: String)</code> somehow. This is one of the advantages of using <code>Symbol</code>: we can use <a href="https://hackage.haskell.org/package/base-4.21.0.0/docs/GHC-TypeLits.html#v:symbolVal"><code class="has-text-link">symbolVal</code></a> to get the value representation of the type-level string, which itself uses the <a href="https://hackage.haskell.org/package/base-4.21.0.0/docs/GHC-TypeLits.html#t:KnownSymbol"><code>KnownSymbol</code> constraint</a>:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">KnownSymbol</span> endpoint <span class="ot">=&gt;</span> <span class="dt">HasLink</span> endpoint <span class="kw">where</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>    toLink proxy baselink <span class="ot">=</span> baselink <span class="op">&lt;&gt;</span> [symbolVal proxy]</span></code></pre></div>
<p>This is a somewhat complicated way of saying that the following example holds:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a>toLink (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> (<span class="st">&quot;endpoint&quot;</span><span class="ot"> ::</span> <span class="dt">Symbol</span>)) [<span class="st">&quot;/&quot;</span>] <span class="op">==</span> [<span class="st">&quot;/&quot;</span>, <span class="st">&quot;endpoint&quot;</span>]</span></code></pre></div>
<p>where <code>Proxy "endpoint"</code> contains the type-level string <code>"endpoint"</code>, while the right-hand side <code>["/", "endpoint"]</code> is a regular value of type <code>[String]</code>.</p>
<p>With this out of the way, we can write instances for all other types of our API. <code>&lt;some symbol&gt; :&gt; subapi</code> is an interesting one because we recursively use <code>toLink</code> forwards and backwards:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">KnownSymbol</span> super, <span class="dt">HasLink</span> sub) <span class="ot">=&gt;</span> <span class="dt">HasLink</span> (super <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>    toLink (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> (super <span class="op">:&gt;</span> sub)) baselink</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>        <span class="ot">=</span>  toLink (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> super) baselink <span class="co">-- backwards</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>        <span class="op">&lt;&gt;</span> toLink (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> sub) []         <span class="co">-- forwards</span></span></code></pre></div>
<p>For example:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>toLink (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> (<span class="st">&quot;forecast&quot;</span> <span class="op">:&gt;</span> <span class="st">&quot;lastupdated&quot;</span>)) [<span class="st">&quot;/&quot;</span>] <span class="op">==</span> [<span class="st">&quot;/&quot;</span>, <span class="st">&quot;forecast&quot;</span>, <span class="st">&quot;lastupdated&quot;</span>]</span></code></pre></div>
<p><code>Capture</code> is last, and we get to re-use <code>symbolVal</code>. This is because we want to represent the name of the capture parameter, sandwiched between <code>&lt;</code> and <code>&gt;</code>:</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">HasLink</span> sub, <span class="dt">KnownSymbol</span> name) <span class="ot">=&gt;</span> <span class="dt">HasLink</span> (<span class="dt">Capture</span> name a <span class="op">:&gt;</span> sub) <span class="kw">where</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>    toLink (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> (<span class="dt">Capture</span> name a <span class="op">:&gt;</span> sub)) baselink</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>        <span class="ot">=</span>  baselink</span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>        <span class="op">&lt;&gt;</span> [<span class="st">&quot;&lt;&quot;</span> <span class="op">&lt;&gt;</span> symbolVal (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> name) <span class="op">&lt;&gt;</span> <span class="st">&quot;&gt;&quot;</span>]</span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>        <span class="op">&lt;&gt;</span> toLink (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> sub) []</span></code></pre></div>
<p>For example:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>toLink (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> (<span class="st">&quot;forecast&quot;</span> <span class="op">:&gt;</span> <span class="dt">Capture</span> <span class="st">&quot;date&quot;</span> <span class="dt">Day</span> <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span>)) [<span class="st">&quot;/&quot;</span>]</span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">==</span> [<span class="st">&quot;/&quot;</span>, <span class="st">&quot;forecast&quot;</span>, <span class="st">&quot;&lt;date&gt;&quot;</span>, <span class="st">&quot;temperature&quot;</span>]</span></code></pre></div>
<p>We’re almost done. We’ll just wrap <code>toLink</code> to make it easier to use. In particular, we want to represent the list of link segments as a single piece of <code>String</code>:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="ot">safeLink ::</span> <span class="dt">HasLink</span> endpoint <span class="ot">=&gt;</span> <span class="dt">Proxy</span> endpoint <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>safeLink endpoint</span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="fu">mconcat</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">$</span> intersperse <span class="st">&quot;/&quot;</span></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">$</span> toLink endpoint [<span class="st">&quot;/&quot;</span>]</span></code></pre></div>
<p>and boom! We are ready to generate links to our type-leven endpoints. Behold:</p>
<!--
This comment prevents the following from being displayed, but it still gets typechecked

\begin{code}
_ = safeLink (Proxy :: Proxy ("forecast" :> Capture "date" Day :> "temperature" :> Get Temperature))
_ = safeLink (Proxy :: Proxy ("weather" :> "temperature" :> Capture "city" City :> ReqBody Temperature :> Post))
\end{code}
-->
<div class="sourceCode" id="cb24"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a> ghci<span class="op">&gt;</span> safeLink (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> (<span class="st">&quot;forecast&quot;</span> <span class="op">:&gt;</span> <span class="dt">Capture</span> <span class="st">&quot;date&quot;</span> <span class="dt">Day</span> <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">Temperature</span>))</span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;/forecast/&lt;date&gt;/temperature&quot;</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a> ghci<span class="op">&gt;</span> safeLink (<span class="dt">Proxy</span><span class="ot"> ::</span> <span class="dt">Proxy</span> (<span class="st">&quot;weather&quot;</span> <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span> <span class="op">:&gt;</span> <span class="dt">Capture</span> <span class="st">&quot;city&quot;</span> <span class="dt">City</span> <span class="op">:&gt;</span> <span class="dt">ReqBody</span> <span class="dt">Temperature</span> <span class="op">:&gt;</span> <span class="dt">Post</span>))</span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a> <span class="st">&quot;/weather/temperature/&lt;city&gt;&quot;</span></span></code></pre></div>
<hr>
<p>This concludes our first derivation from an API that can be represented by types. This allowed us to create links to endpoints in our API, while ensuring that if an endpoint exists, links to it will be valid. Otherwise, we get a compile-time error!</p>
<p>I wanted to show you this first, because we got acquainted with <a href="https://hackage.haskell.org/package/base-4.21.0.0/docs/Data-Proxy.html#t:Proxy"><code class="has-text-link">Proxy</code></a>, a type that is often seen to help with inference of complex types.</p>
<p>The constructs you have seen in this post are all part of the Servant codebase, although I have simplified things here. This includes <a href="https://hackage.haskell.org/package/servant-0.20.2/docs/Servant-API.html#v:safeLink"><code class="has-text-link">safeLink</code></a>, and the <a href="https://hackage.haskell.org/package/servant-0.20.2/docs/Servant-API.html#t:HasLink"><code class="has-text-link">HasLink</code></a> typeclass. The real <a href="https://hackage.haskell.org/package/servant-0.20.2/docs/Servant-API.html#v:safeLink"><code class="has-text-link">safeLink</code></a> function is notably more powerful for two reasons:</p>
<ul>
<li>You get a compile time error if the endpoint isn’t part of the given API. This means you get even more certainty that the link is valid;</li>
<li>You can feed <code>safeLink</code> the values that go in <code>Capture</code> and <code>QueryParam</code>, to get the true link to the endpoint, rather than having e.g. a <code>&lt;date&gt;</code> placeholder.</li>
</ul>
<p>In the next post, we will go one step further: checking the shape of the server handlers at compile-time. This will require us to use <code>Proxy</code> again, but we’ll also learn about how type families, or type functions, fit in all of this.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>The Servant implementation is more powerful; it gives a type error if the link would point to something that isn’t part of the API we specify. This introduces too much complexity for this blog post, but we may revisit this later.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></summary>
</entry>
<entry>
    <title>An API as a type - Servant by construction part 1</title>
    <link href="https://laurentrdc.xyz//posts/servant-by-construction/ApiAsType.html" />
    <id>https://laurentrdc.xyz//posts/servant-by-construction/ApiAsType.html</id>
    <published>2025-09-27T00:00:00Z</published>
    <updated>2025-10-30</updated>
    <summary type="html"><![CDATA[<p>This file is a Literate Haskell module, so we have to get some ceremony out-of-the-way.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE DerivingStrategies #-}</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- We&#39;ll get back to DataKinds</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE DataKinds #-}</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">ApiAsType</span> <span class="kw">where</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- we&#39;ll need these later on</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Text</span> (<span class="dt">Text</span>)</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Time</span> (<span class="dt">UTCTime</span>, <span class="dt">Day</span>)</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">GHC.TypeLits</span> (<span class="dt">Symbol</span>)</span></code></pre></div>
<p>A web application programming interface (API) can be represent by a tree of endpoints<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>. The foundational idea behind Servant is that this tree of endpoints can be represented as one type. This API type is constructed by using higher-order types to compose endpoints together.</p>
<p>This foundational idea leads to most of Servant’s power. First, moving data into types helps tremendously with ensuring correctness, as we will soon see. Second, we can <em>derive</em> functionality on demand for our API type using typeclasses. This last sentence is wholly uninformative unless you already know Servant, so please bear with me here while we construct examples.</p>
<p>For the remainder of this blog series, we will consider an example, concrete API. This isn’t a lesson in API design. For simplicity, we assume that all data to and from the server will be encoded in plain text (although we may extend this in later posts).</p>
<p>The example API is a weather API which deals with measurements and forecasts of outdoor temperature. Here are the endpoints:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode txt"><code class="sourceCode default"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>-- Returns the time at which forecasts we last updated.</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>GET /forecast/lastupdated</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>-- Returns the forecasted temperature on a (future) date for all known places.</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>-- The date is captured from the endpoint, e.g. &quot;/forecast/2025-06-01/temperature&quot;</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>-- should return the temperature forecasted for June 1st, 2025</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>GET /forecast/&lt;date&gt;/temperature</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>-- Returns the temperature on this current date. The city is expected to</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>-- be passed as a required query parameter, e.g. &quot;/weather/temperature&amp;city=Montreal&quot;</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>GET /weather/temperature&amp;city=&lt;city&gt;</span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>-- Record a temperature measurement posted by someone for a given city</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>POST /weather/temperature/&lt;city&gt;</span></code></pre></div>
<p>This example API has a good mixture of methods (GET and POST), query parameters, and path parameters. Let’s create some types to help us describe this API.</p>
<p>First, we want to extend routes. For example, <code>/forecast/lastupdated</code> and <code>/forecast/&lt;date&gt;/temperature</code> share the root <code>forecast</code>:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> a <span class="op">:&gt;</span> b</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">infixr</span> <span class="dv">4</span> <span class="op">:&gt;</span></span></code></pre></div>
<p>Haskell is known for using all sorts of non-standard character sequences <em>as functions</em>, like <code>(&gt;&gt;=)</code>. Well, you can do the same for types! Example usage for <code>(:&gt;)</code>:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Forecast</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">LastUpdated</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">LastUpdatedForecast</span> <span class="ot">=</span> <span class="dt">Forecast</span> <span class="op">:&gt;</span> <span class="dt">LastUpdated</span></span></code></pre></div>
<p>Wait a second – aren’t path segments strings, like <code>"forecast"</code> and <code>"lastupdated"</code>? Why isn’t the definition <code>data String :&gt; String</code>? This is the power of Servant, but also the source of its complexity: APIs are meant to represented by <em>types</em>, that the compiler can check at compile-time. Instead of every piece of our API being a different string of the same type, they are all a different <em>type</em>. For now, trust me that this is worth doing.</p>
<p>APIs defined in Servant use tons of bespoke types, like <code>Forecast</code> and <code>LastUpdated</code> above. To save on the boilerplate of defining a bunch of these types, people typically use the <a href="https://downloads.haskell.org/ghc/9.12.2/docs/users_guide/exts/data_kinds.html#extension-DataKinds"><code class="has-text-link">DataKinds</code></a> extension, which is enabled in this module. With it, instead of:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Root</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Branch</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Leaf</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Tree1</span> <span class="ot">=</span> <span class="dt">Root</span> <span class="op">:&gt;</span> <span class="dt">Branch</span> <span class="op">:&gt;</span> <span class="dt">Leaf</span></span></code></pre></div>
<p>we can write:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Tree2</span> <span class="ot">=</span> <span class="st">&quot;root&quot;</span> <span class="op">:&gt;</span> <span class="st">&quot;branch&quot;</span> <span class="op">:&gt;</span> <span class="st">&quot;leaf&quot;</span></span></code></pre></div>
<p><code>"root"</code>, <code>"branch"</code>, and <code>"leaf"</code> are type-level strings, which have kind <code>Symbol</code>, and you will see that they have advantages that we’ll see later on.</p>
<p>Allright, now we can compose path segments into long path segments using <code>(:&gt;)</code>. What about describing the endpoint? For example, <code>GET /forecast/lastupdated</code> should return the time at which the forecast was last updated. We can define a type to specify this:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Get</span> a</span></code></pre></div>
<p>where <code>a</code> is the return type of this endpoint. At last, we can express the full type of <em>one</em> of our endpoints:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">GetForecastLastUpdated</span> <span class="ot">=</span> <span class="st">&quot;forecast&quot;</span> <span class="op">:&gt;</span> <span class="st">&quot;lastupdated&quot;</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">UTCTime</span></span></code></pre></div>
<p>You might be wondering why our <code>Get</code> doesn’t have a constructor. Why not:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Get</span> a <span class="ot">=</span> <span class="dt">MkGet</span> {<span class="ot">unGet ::</span> a}</span></code></pre></div>
<p>The reason is that our API will not exist in this form at runtime. As you will see later on, we will derive things from our API, and these derivations will be used at runtime, but not the API itself.</p>
<p>Let’s tackle the second endpoint, <code>GET /forecast/&lt;date&gt;/temperature</code>. This endpoint is interesting because we want to <em>capture</em> some date, to be used when processing the request. To do this, we’ll create yet another type:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Capture</span> (<span class="ot">name ::</span> <span class="dt">Symbol</span>) a</span></code></pre></div>
<p>where <code>name</code> will represent some parameter name, which will be useful later on, and <code>a</code> is the type being captured. Recall that in this case, <code>name</code> is a <code>Symbol</code>, or type-level string, and not a real <code>String</code>. Our <code>GET /forecast/&lt;date&gt;/temperature</code> can thus be represented by:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Type representing temperature in Celsius</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Temperature</span> <span class="ot">=</span> <span class="dt">MkTemperature</span> <span class="dt">Double</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> <span class="kw">newtype</span> (<span class="dt">Eq</span>, <span class="dt">Show</span>, <span class="dt">Read</span>, <span class="dt">Num</span>)</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">GetForecastTemperature</span> <span class="ot">=</span> <span class="st">&quot;forecast&quot;</span> <span class="op">:&gt;</span> <span class="dt">Capture</span> <span class="st">&quot;date&quot;</span> <span class="dt">Day</span> <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">Temperature</span></span></code></pre></div>
<p>The two API endpoints we’ve defined so far, have the same root (<code>forecast</code>). It’s often useful to define relate endpoints sharing the same root together – for example, to define authentication which should apply to all related endpoints. We will create a type to represent the branching of endpoints:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> a <span class="op">:&lt;|&gt;</span> b <span class="ot">=</span> a <span class="op">:&lt;|&gt;</span> b</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- We want :&lt;|&gt; to have a lower precedence than :&gt; so that we can</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- write API definitions without tons of parentheses</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="kw">infixr</span> <span class="dv">3</span> <span class="op">:&lt;|&gt;</span></span></code></pre></div>
<p>With <code>:&lt;|&gt;</code>, we can write our forecast endpoints as :</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">ForecastRoutes</span> <span class="ot">=</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;forecast&quot;</span> <span class="op">:&gt;</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>            ( <span class="st">&quot;lastupdated&quot;</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>                    <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">UTCTime</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>            <span class="op">:&lt;|&gt;</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>                <span class="dt">Capture</span> <span class="st">&quot;date&quot;</span> <span class="dt">Day</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>                    <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>                        <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">Temperature</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>            )</span></code></pre></div>
<p>which is formatted to look like a tree:</p>
<pre><code>forecast
 ├─lastupdated
 │  └─GET UTCTime
 └─&lt;date&gt;
    └─temperature
       └─GET Temperature</code></pre>
<p>The next endpoint, <code>GET /weather/temperature&amp;city=&lt;city&gt;</code>, has a new wrinkle: an (optional) query parameter. This warrants a new type:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">QueryParam</span> (<span class="ot">name ::</span> <span class="dt">Symbol</span>) a</span></code></pre></div>
<p>such that we can write:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">City</span> <span class="ot">=</span> <span class="dt">MkCity</span> <span class="dt">Text</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> <span class="kw">newtype</span> (<span class="dt">Show</span>, <span class="dt">Read</span>)</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">GetTemperature</span> <span class="ot">=</span> <span class="st">&quot;weather&quot;</span> <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span> <span class="op">:&gt;</span> <span class="dt">QueryParam</span> <span class="st">&quot;city&quot;</span> <span class="dt">City</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">Temperature</span></span></code></pre></div>
<p>For the last endpoint, <code>POST /weather/temperature/&lt;city&gt;</code>, we need two last constructs. In a POST request, the <em>request body</em> will contain some data for the server to process (in the case of our endpoint, this data will be a temperature measurement in plaintext). Moreover, in our example, the POST request will return no data. For our API description to be adequate, we must describe the request body and the lack of data returned with – you guessed it – new types:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Post</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">ReqBody</span> a</span></code></pre></div>
<p>The endpoint description becomes:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">PostTemperature</span> <span class="ot">=</span> <span class="st">&quot;weather&quot;</span> <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span> <span class="op">:&gt;</span> <span class="dt">Capture</span> <span class="st">&quot;city&quot;</span> <span class="dt">City</span> <span class="op">:&gt;</span> <span class="dt">ReqBody</span> <span class="dt">Temperature</span> <span class="op">:&gt;</span> <span class="dt">Post</span></span></code></pre></div>
<p>Let’s structure all of our endpoints into a single type:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">ForecastAPI</span> <span class="ot">=</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>        <span class="st">&quot;forecast&quot;</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>            <span class="op">:&gt;</span> ( <span class="st">&quot;lastupdated&quot;</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">UTCTime</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>            <span class="op">:&lt;|&gt;</span> <span class="dt">Capture</span> <span class="st">&quot;date&quot;</span> <span class="dt">Day</span> <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">Temperature</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>               )</span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">WeatherAPI</span> <span class="ot">=</span></span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;weather&quot;</span></span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a>        <span class="op">:&gt;</span> <span class="st">&quot;temperature&quot;</span></span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a>            <span class="op">:&gt;</span> ( <span class="dt">QueryParam</span> <span class="st">&quot;city&quot;</span> <span class="dt">City</span> <span class="op">:&gt;</span> <span class="dt">Get</span> <span class="dt">Temperature</span></span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a>            <span class="op">:&lt;|&gt;</span> <span class="dt">Capture</span> <span class="st">&quot;city&quot;</span> <span class="dt">City</span> <span class="op">:&gt;</span> <span class="dt">ReqBody</span> <span class="dt">Temperature</span> <span class="op">:&gt;</span> <span class="dt">Post</span></span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a>               )</span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">API</span> <span class="ot">=</span> <span class="dt">ForecastAPI</span> <span class="op">:&lt;|&gt;</span> <span class="dt">WeatherAPI</span></span></code></pre></div>
<p>Enough new types; let’s recap what we have created so far:</p>
<ul>
<li>We created a type <code>:&gt;</code> to build endpoint paths from segments;</li>
<li>We created a type <code>:&lt;|&gt;</code> to build branching paths;</li>
<li>We created a type <code>Capture</code> to capture data in endpoint paths;</li>
<li>We created a type <code>QueryParam</code> to specify the name and type of optional query parameters;</li>
<li>We created a type <code>ReqBody</code> to specify the type of the body of a POST request;</li>
<li>We created types <code>Get</code> and <code>Post</code> to represent the verb of a request;</li>
<li>We created a type, <code>API</code>, built up from smaller types <code>ForecastAPI</code> and <code>WeatherAPI</code>, which can be used to describe all of our API.</li>
</ul>
<p>It bears repeating: none of the types defined above have constructors, which means that the type of our API, <code>API</code>, cannot even be instantiated at runtime! All functionality that will have to do with our API will come from deriving things from its definition <strong>at compile time</strong>.</p>
<p>In the next post, we will start from the <code>API</code> type and its endpoints, and derive something from them. This derivation will introduce us to the machinery that powers much of Servant’s functionality.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>Although endpoints are usually not <em>shown</em> as a tree (for example, in an OpenAPI specification, endpoints are listed), routing requests is obviously more efficient if routes are <em>stored</em> as a tree.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></summary>
</entry>
<entry>
    <title>Servant by construction - a blog series on Haskell's web stack gem</title>
    <link href="https://laurentrdc.xyz//posts/servant-by-construction-introduction.html" />
    <id>https://laurentrdc.xyz//posts/servant-by-construction-introduction.html</id>
    <published>2025-09-26T00:00:00Z</published>
    <updated>2025-11-13</updated>
    <summary type="html"><![CDATA[<p><em>Featured in <a href="https://haskellweekly.news/issue/498.html">Haskell Weekly issue 498</a></em></p>
<p>A large fraction of software engineers work in web development.</p>
<p>I also do some web development these days, exclusively on the backend. Backend software engineers, just like their frontend counterparts, have streamlined their work by packaging development utilities into <em>frameworks</em>. Even in the relatively small Haskell community, there are many web frameworks, ranging from quick-to-start (<a href="https://github.com/scotty-web/scotty">scotty</a>) to fully-featured-and-opinionated (<a href="https://www.yesodweb.com/">Yesod</a> and <a href="https://ihp.digitallyinduced.com/">IHP</a>).</p>
<p>The Haskell community has historically been fertile ground for innovation; web development is no different. One framework in particular has pushed the boundary of what it means to write web applications: <a href="https://www.servant.dev/">Servant</a>.
Don’t be fooled by the deceptively simplistic website: Servant is one of the crown jewels of the Haskell ecosystem. It combines the broad appeal of writing web applications, with the use of some of Haskell’s most advanced type system features to perform incredible feats of engineering.</p>
<p>Servant is worth discussing and studying for two reasons.</p>
<p>The first is to use Servant as a concrete application of type-level computation. In this respect, I hope readers can take some of the design ideas from Servant and bring it back to their community, just like <a href="https://hackage.haskell.org/package/QuickCheck">QuickCheck</a> pioneered property-based testing.
The second is that while Servant is powerful, it remains a rather sophisticated piece of software that is hard to learn and understand. Even with some Haskell experience, Servant is not yet a pick-up-and-go tool; wandering off the beaten path (i.e. doing anything not covered in the <a href="https://docs.servant.dev/">documentation</a>) remains a daunting prospect for many, as it was for me. By studying the inner workings of Servant, we can learn about how to use it, and extend it, effectively.</p>
<p>I want to celebrate the boldness of Servant, while teaching you about its ways. This is why I am starting a <em>blog series</em>, where I will cover the basics of Servant by <em>implementing</em> a simple version of Servant’s internals, as literate Haskell files. By <em>constructing</em> Servant, we will both learn various techniques involving Haskell’s advanced type system, but also demystify the real Servant library.</p>
<p>This blog series will build in complexity. We will start by representing an API as a type. This type won’t be useful straight away, but subsequent blog posts will showcase one capability of Servant by using this type, starting with generating type-safe links to endpoints, and culminating with automatically generating clients of APIs.</p>
<p><strong>Blog posts in this series</strong></p>
<ul>
<li><a href="/posts/servant-by-construction/ApiAsType.html">An API as a type</a></li>
<li><a href="/posts/servant-by-construction/TypeSafeLinks.html">Type-safe links</a></li>
<li><a href="/posts/servant-by-construction/ServingAnApi.html">Serving an API</a></li>
<li><a href="/posts/servant-by-construction/GeneratingAClient.html">Automatic derivation of client functions</a></li>
</ul>
<p><em>Update</em></p>
<p>This is the end of the planned posts in the Servant by construction series. If there’s another Servant-related topic you’d like to learn more about, by having me build a simplified version, don’t hesitate to reach out!</p>]]></summary>
</entry>
<entry>
    <title>I joined the Haskell Foundation's board of directors</title>
    <link href="https://laurentrdc.xyz//posts/joined-hf-board.html" />
    <id>https://laurentrdc.xyz//posts/joined-hf-board.html</id>
    <published>2025-07-08T00:00:00Z</published>
    <updated>2025-07-08</updated>
    <summary type="html"><![CDATA[<p>As you can see from this website, I am quite involved in the Haskell community. Well, I went a step further by applying to join, and then being elected to, the <a href="https://haskell.foundation">Haskell Foundation</a>’s <a href="https://haskell.foundation/who-we-are/">board of directors</a>.</p>
<p><a href="https://haskell.foundation/vision/">The Haskell Foundation is driven by a vision</a>. Haskell has a rich history of academic research, innovation, and industry usage driven by strong principles. Within this vision, I personally want focus on boosting the community’s health on two fronts.</p>
<p>The first front is <strong>industry adoption</strong>. I took a new Haskell-focused role this year, and Haskell’s unique strengths – as well as unique challenges – are front-of-mind. The Haskell Foundation is ramping up efforts to spend resources on its technical agenda. If you use, or plan to use, Haskell in production, we would love to hear how we can help you (contact info at the end of this post).</p>
<p>The second front is the <strong>successful conversion of Haskell curiousity to Haskell knowledge</strong>, especially amongst experienced programmers. Over the years, I have spoken with many, <em>many</em> people whose curiosity, although intense, did not materialize into knowledge of Haskell. My own experience of learning and using Haskell was, and remains, a wonderful intellectual journey, and I want everyone to be able to experience the same thing. I’ll have more to say about how we plan to tackle this in the next few months.</p>
<p>If any of these two challenges are of interest to you, do not hesitate to reach out to me at my new email (<a href="mailto:laurent@haskell.foundation">laurent@haskell.foundation</a>).</p>]]></summary>
</entry>
<entry>
    <title>Modeling dataframes in Haskell using higher-kinded types</title>
    <link href="https://laurentrdc.xyz//posts/HKTGenerics.html" />
    <id>https://laurentrdc.xyz//posts/HKTGenerics.html</id>
    <published>2025-01-22T00:00:00Z</published>
    <updated>2025-11-06</updated>
    <summary type="html"><![CDATA[<p><em>Featured in <a href="https://haskellweekly.news/issue/456.html">Haskell Weekly issue 456</a></em></p>
<p>I am a firm believer in the purely functional programming approach, embodied by the Haskell programming language. While the Haskell
community is not huge, it is large enough that I can work on most domains.</p>
<p>Most domains, but not all; data science remains hard to work on in Haskell. Since data science grew out not from software engineering,
but from students and scientists, the best data science tools are found in other communities such as <a href="https://www.r-project.org/">R</a> and
<a href="https://www.python.org/">Python</a>. If we focus further on machine-learning and “““AI”“” (ಠ_ಠ), then the distribution of high-quality
tools is even more concentrated in the Python community.</p>
<p>I have started exploring what it would look like to build a Haskell-centric data science workflow more than a year ago, with the
implementation of a <a href="https://hackage.haskell.org/package/javelin-0.1.4.1/docs/Data-Series-Tutorial.html">Series data structure</a>.
While this was perfect for my use-case at the time (I wrote about it <a href="/posts/rolling-stats.html">here</a>
and <a href="/posts/typesafe-tradingstrats.html">here</a>), the typical data scientist is used to columnar the data structure known as the
<em>dataframe</em>.</p>
<p>Recently, an effort to <a href="https://discourse.haskell.org/t/design-dataframes-in-haskell/11108">design a dataframe interface</a> in Haskell
has been spearheaded by Michael Chavinda, with a focus on exploratory data science. This effort trades type safety for easier
interactivity, similar to <a href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html">Python’s pandas DataFrames</a>.</p>
<p>In this blog post, I want to explore a different design tradeoff: what if one were to instead focus on type-safe expressiveness, with
no regards to interactivity? What would such a dataframe interface look like?</p>
<p>The design below is based on some intermediate type-level shenanigans. I was inspired by the approach that
the <a href="https://github.com/haskell-beam/beam">Beam SQL project</a> took, based on higher-kinded types.</p>
<p>Let’s get imports out of the way:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE DefaultSignatures #-}</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE DeriveGeneric #-}</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE TypeFamilies #-}</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">HKTGenerics</span> <span class="kw">where</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- from `base`</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Functor.Identity</span> (<span class="dt">Identity</span>(..))</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Kind</span> (<span class="dt">Type</span>)</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">GHC.Generics</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- from `vector`</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Vector</span> (<span class="dt">Vector</span>)</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Vector</span></span></code></pre></div>
<p>Let’s consider an example: we want to represent a set of people of some sort. We would normally represent
one person using a record type like so:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">SimpleUser</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkSimpleUser</span> {<span class="ot"> simpleUserFirstName ::</span> <span class="dt">String</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>                   ,<span class="ot"> simpleUserLastName  ::</span> <span class="dt">String</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>                   ,<span class="ot"> simpleUserAge       ::</span> <span class="dt">Int</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>                   }</span></code></pre></div>
<p>Now, a <em>dataframe</em> of such users should be equivalent to:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">FrameUser</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkFrameUser</span> {<span class="ot"> frameUserFirstName ::</span> <span class="dt">Vector</span> <span class="dt">String</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>                  ,<span class="ot"> frameUserLastName  ::</span> <span class="dt">Vector</span> <span class="dt">String</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>                  ,<span class="ot"> frameUserAge       ::</span> <span class="dt">Vector</span> <span class="dt">Int</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>                  }</span></code></pre></div>
<p>where each record is a <code>Vector</code> (similar to arrays in other languages), representing a column. This is the main draw of dataframes:
data is stored in columns, rather than simply e.g. <code>Vector SimpleUser</code>. This is not always best, but I will assume that the user
has knowledge of the tradeoffs.</p>
<p>The structures of <code>SimpleUser</code> and <code>FrameUser</code> are extremely similar. We can use higher-kinded types to unify them by introducing a
type parameter <code>f</code> which represents the container for values:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">HKTUser</span> f</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkHKTUser</span> {<span class="ot"> hktUserFirstName ::</span> f <span class="dt">String</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>                ,<span class="ot"> hktUserLastName  ::</span> f <span class="dt">String</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>                ,<span class="ot"> hktUserAge       ::</span> f <span class="dt">Int</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>                }</span></code></pre></div>
<p>Here, <code>f</code> has type <code>f :: Type -&gt; Type</code>, just like the <code>Vector</code> type constructor. <code>HKTUser</code> is called a higher-kinded type, because
unlike a type like <code>SimpleUser</code>, which has kind <code>Type</code>, <code>HKTUser</code> isn’t a type, but a <em>type constructor</em>. I won’t go into more detail
than this on higher-kinded types; consider watching the <a href="https://www.youtube.com/live/EXgsXy1BR-0?si=9CMdb_wHJvCNfNYr">Haskell Unfolder episode on the subject</a>.</p>
<p>Using this method of representing users, we can represent <code>SimpleUser</code> as <code>HKTUser Identity</code>, and <code>FrameUser</code> as <code>HKTUser Vector</code>.
Here, <a href="https://hackage.haskell.org/package/base-4.21.0.0/docs/Data-Functor-Identity.html"><code class="has-text-link">Identity</code></a> is the trivial container.</p>
<p>One more thing before we move on. While <code>Identity</code> is a trivial functor, it still adds some overhead; <code>HKTUser Identity</code> and <code>SimpleUser</code>
aren’t <em>exactly</em> equivalent. We can optimize this overhead away using a type family:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="kw">family</span> <span class="dt">Column</span> (<span class="ot">f ::</span> <span class="dt">Type</span> <span class="ot">-&gt;</span> <span class="dt">Type</span>) x <span class="kw">where</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Column</span> <span class="dt">Identity</span> x <span class="ot">=</span> x <span class="co">-- Optimization</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">Column</span> <span class="dt">Vector</span> x <span class="ot">=</span> <span class="dt">Vector</span> x</span></code></pre></div>
<p>Finally, we can unify the representations of <code>SimpleUser</code> and <code>FrameUser</code>:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">User</span> f</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkUser</span> {<span class="ot"> userFirstName ::</span> <span class="dt">Column</span> f <span class="dt">String</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>             ,<span class="ot"> userLastName  ::</span> <span class="dt">Column</span> f <span class="dt">String</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>             ,<span class="ot"> userAge       ::</span> <span class="dt">Column</span> f <span class="dt">Int</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>             }</span></code></pre></div>
<p>The <code>Column</code> type family can be thought of a <em>type-level function</em>: <code>Column f a</code> is a type that depends on <code>f</code>. To be clearer, let’s
create type synonyms:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Row</span>   (<span class="ot">dt ::</span> (<span class="dt">Type</span> <span class="ot">-&gt;</span> <span class="dt">Type</span>) <span class="ot">-&gt;</span> <span class="dt">Type</span>) <span class="ot">=</span> dt <span class="dt">Identity</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Frame</span> (<span class="ot">dt ::</span> (<span class="dt">Type</span> <span class="ot">-&gt;</span> <span class="dt">Type</span>) <span class="ot">-&gt;</span> <span class="dt">Type</span>) <span class="ot">=</span> dt <span class="dt">Vector</span></span></code></pre></div>
<p>Using these synonyms, <code>Row User</code> is equivalent to <code>SimpleUser</code>. while <code>Frame User</code> is equivalent to <code>FrameUser</code>. We can operate on the
columns of dataframes easily, like so:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- | Returns the longest first name out of a dataframe of users.</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- If the dataframe is empty, returns the empty string.</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ot">longestFirstName ::</span> <span class="dt">Frame</span> <span class="dt">User</span> <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>longestFirstName <span class="ot">=</span> Data.Vector.foldl&#39; longest <span class="fu">mempty</span> <span class="op">.</span> userFirstName</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="ot">        longest ::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>        longest x y <span class="ot">=</span> <span class="kw">if</span> <span class="fu">length</span> x <span class="op">&gt;=</span> <span class="fu">length</span> y <span class="kw">then</span> x <span class="kw">else</span> y</span></code></pre></div>
<p>With <code>longestFirstName</code>, we can glimpse the performance advantage of using dataframes: the <code>userFirstName</code> field is really
an array, and so finding the longest first name is an operation on an array of string rather than an array of <code>User</code>.</p>
<p>How can we build a dataframe? We can turn rows of, well, <code>Row User</code> into a single <code>Frame User</code> like so:
<!--
    Using the markdown syntax below will prevent the Haskell compiler
    from looking at the code
--></p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ot">buildUserFrame ::</span> <span class="dt">Vector</span> (<span class="dt">Row</span> <span class="dt">User</span>) <span class="ot">-&gt;</span> <span class="dt">Frame</span> <span class="dt">User</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>buildUserFrame vs</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkUser</span> { userFirstName <span class="ot">=</span> Data.Vector.map userFirstName vs</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>             , userLastName  <span class="ot">=</span> Data.Vector.map userLastName vs</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>             , userAge       <span class="ot">=</span> Data.Vector.map userAge vs</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>             }</span></code></pre></div>
<p>This is a little tedious; for every type of dataframe, we need to write our own dataframe construction function!
Can we write a function like <code class="sourceCode haskell"><span class="dt">Vector</span> (<span class="dt">Row</span> t) <span class="ot">-&gt;</span> <span class="dt">Frame</span> t</code>, which works for any <code>t</code>? Yes we can.</p>
<h2 class="title is-2" id="enter-generics">Enter generics</h2>
<p><em>I want to thank <strong>Li-yao Xia</strong> (Lysxia on the <a href="https://discourse.haskell.org/">Haskell Discourse</a>) for helping me
figure out how to do what you’re about to read!</em></p>
<p>If you squint, every type we would want to turn into a dataframe has the same structure: a record type where every record
is either <code>Vector a</code> or <code>Identity a</code> (nesting dataframes is out of scope for today). We can provide functionality for any
suitable record type like that using Haskell generics<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>.</p>
<p>In Haskell, the <code>Generic</code> typeclass has nothing to do with “generics” in other programming language. “Generic” programming in Haskell is done
with ad-hoc polymorphism (i.e. typeclasses). Instead, the <code>Generic</code> typeclass in Haskell is used to transform any datatype <code>t</code> into
a generic representation, called <code>Rep t</code>, which can be used define functions which work over a large class
of types. Specifically, in our case, we want to create a function <code class="sourceCode haskell"><span class="dt">Vector</span> (<span class="dt">Row</span> t) <span class="ot">-&gt;</span> <span class="dt">Frame</span> t</code> which works
for <strong>any higher-kinded record type</strong> <code>t</code> like <code>User</code>.</p>
<p>There are many explanations of Haskell’s <code>Generic</code>, such as <a href="https://markkarpov.com/tutorial/generics.html">Mark Karpov’s Generics explained</a>
blog post. The wrinkle in our dataframe problem is that types such as <code>User</code> are higher-kinded, and therefore some more care
is required.</p>
<p>Let’s define our problem. We want to create a typeclass <code>FromRows</code> with a method, <code>fromRows</code>:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">FromRows</span> t <span class="kw">where</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    fromRows ::</span> <span class="dt">Vector</span> (<span class="dt">Row</span> t) <span class="ot">-&gt;</span> <span class="dt">Frame</span> t</span></code></pre></div>
<p>We also want to provide a default definition of <code>fromRows</code> such that downstream users don’t have to manually write instances
of <code>FromRows</code>:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>    default<span class="ot"> fromRows ::</span> (<span class="op">???</span>) <span class="ot">=&gt;</span> <span class="dt">Vector</span> (<span class="dt">Row</span> t) <span class="ot">-&gt;</span> <span class="dt">Frame</span> t</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>    fromRows <span class="ot">=</span> <span class="op">???</span></span></code></pre></div>
<p>How can we write the default implementation of <code>fromRows</code>?</p>
<p>The key concept to remember is that <code>Generic</code> only works with types of kind <code>Type</code>, i.e. <code>Row User</code> but not <code>User</code>. For every
higher-kinded type <code>t</code> (like <code>User</code>), we care about two concrete types: <code>Row t</code> and <code>Frame t</code>. Therefore, we need to index our
typeclass on both concrete types at once.</p>
<p>Enough word salad:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">GFromRows</span> r <span class="co">-- intended to be `Row`-like</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>                f <span class="co">-- intended to be `Frame`-like</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="ot">    gfromRows ::</span> <span class="dt">Vector</span> (r a) <span class="ot">-&gt;</span> (f a)</span></code></pre></div>
<p>We need to provide instances relating to some (<a href="https://hackage.haskell.org/package/base-4.21.0.0/docs/GHC-Generics.html#g:14">but not all</a>)
generic constructs, including <code>M1</code> (which is always required), <code>K1</code>, and <code>(:*:)</code>.</p>
<p>We start with the generic metadata type, <code>M1</code>:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">GFromRows</span> r f <span class="ot">=&gt;</span> <span class="dt">GFromRows</span> (<span class="dt">M1</span> i c r) (<span class="dt">M1</span> i c f) <span class="kw">where</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    gfromRows ::</span> <span class="dt">Vector</span> (<span class="dt">M1</span> i c r a) <span class="ot">-&gt;</span> <span class="dt">M1</span> i c f a</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    gfromRows <span class="ot">=</span> <span class="dt">M1</span> <span class="op">.</span> gfromRows <span class="op">.</span> Data.Vector.map unM1</span></code></pre></div>
<p>Then move on to <code>:*:</code>:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> ( <span class="dt">GFromRows</span> r1 f1</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>         , <span class="dt">GFromRows</span> r2 f2</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>         )</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>         <span class="ot">=&gt;</span> <span class="dt">GFromRows</span> (r1 <span class="op">:*:</span> r2) (f1 <span class="op">:*:</span> f2) <span class="kw">where</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    gfromRows vs <span class="ot">=</span> <span class="kw">let</span> (xs, ys) <span class="ot">=</span> Data.Vector.unzip</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>                                <span class="op">$</span> Data.Vector.map (\(x <span class="op">:*:</span> y) <span class="ot">-&gt;</span> (x, y)) vs</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">in</span> gfromRows xs <span class="op">:*:</span> gfromRows ys</span></code></pre></div>
<p>Finally, onto the representation of fields of constructors, <code>K1</code>:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">GFromRows</span> (<span class="dt">K1</span> i r) (<span class="dt">K1</span> i f) <span class="kw">where</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>    gfromRows <span class="ot">=</span> <span class="dt">K1</span> <span class="op">.</span> Data.Vector.map unK1</span></code></pre></div>
<p>Note that the above will not compile. For the instances of <code>M1</code> and <code>:*:</code>, we assumed that <code>r</code> and <code>f</code> already had an instance
of <code>GFromRows</code>. In the instance for <code>K1</code>, the compiler does not know about the relationship between <code>r</code> and <code>f</code> yet. In
some sense, the instance involving the representation <code>K1</code> is the foundation on which other instances are defined.</p>
<p>We can refine our instance by enforcing that <code>f</code> be an array of <code>r</code> using <code>(f ~ Vector r)</code>:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (f <span class="op">~</span> <span class="dt">Vector</span> r) <span class="ot">=&gt;</span> <span class="dt">GFromRows</span> (<span class="dt">K1</span> i r) (<span class="dt">K1</span> i f) <span class="kw">where</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    gfromRows ::</span> <span class="dt">Vector</span> (<span class="dt">K1</span> i r a) <span class="ot">-&gt;</span> <span class="dt">K1</span> i f a</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>    gfromRows <span class="ot">=</span> <span class="dt">K1</span> <span class="op">.</span> Data.Vector.map unK1</span></code></pre></div>
<p>We can now fill in the default implementation of <code>fromRows</code>:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">FromRows</span> t <span class="kw">where</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="ot">    fromRows ::</span> <span class="dt">Vector</span> (<span class="dt">Row</span> t) <span class="ot">-&gt;</span> <span class="dt">Frame</span> t</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>    default<span class="ot"> fromRows ::</span> ( <span class="dt">Generic</span> (<span class="dt">Row</span> t)</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>                        , <span class="dt">Generic</span> (<span class="dt">Frame</span> t)</span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>                        , <span class="dt">GFromRows</span> (<span class="dt">Rep</span> (<span class="dt">Row</span> t)) (<span class="dt">Rep</span> (<span class="dt">Frame</span> t))</span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>                        )</span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>                     <span class="ot">=&gt;</span> <span class="dt">Vector</span> (<span class="dt">Row</span> t)</span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>                     <span class="ot">-&gt;</span> <span class="dt">Frame</span> t</span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>    fromRows <span class="ot">=</span> to                   <span class="co">-- Turn `Rep (Frame t)` back into `Frame t`</span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>             <span class="op">.</span> gfromRows            <span class="co">-- Vector (Rep (Row t)) -&gt; Rep (Frame t)</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>             <span class="op">.</span> Data.Vector.map from <span class="co">-- Turn every row into a `Reo (Row t)`</span></span></code></pre></div>
<p>How can we use this? Behold:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">User</span> f</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkUser</span> {<span class="ot"> userFirstName ::</span> <span class="dt">Column</span> f <span class="dt">String</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>             ,<span class="ot"> userLastName  ::</span> <span class="dt">Column</span> f <span class="dt">String</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>             ,<span class="ot"> userAge       ::</span> <span class="dt">Column</span> f <span class="dt">Int</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>             }</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> (<span class="dt">Generic</span>) <span class="co">-- This is new</span></span></code></pre></div>
<p>What’s new here is that we need to derive a <code>Generic</code> instance for <code>User</code>. Then, the instance of <code>FromRows User</code> requires
no method implementation:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">FromRows</span> <span class="dt">User</span></span></code></pre></div>
<p>Then, we can re-implement <code>buildUserFrame</code> trivially:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="ot">buildUserFrame ::</span> <span class="dt">Vector</span> (<span class="dt">Row</span> <span class="dt">User</span>) <span class="ot">-&gt;</span> <span class="dt">Frame</span> <span class="dt">User</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>buildUserFrame <span class="ot">=</span> fromRows</span></code></pre></div>
<h2 class="title is-2" id="further-work-nesting-dataframes">Further work: nesting dataframes</h2>
<p>The implementation above works, but we assumed that every record type had fields of the form <code>Column f a</code>.
How about nesting dataframes types? Consider this:</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Address</span> f</span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkAddress</span> {<span class="ot"> addressCivicNumber ::</span> <span class="dt">Column</span> f <span class="dt">Int</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>                ,<span class="ot"> addressStreetName  ::</span> <span class="dt">Column</span> f <span class="dt">String</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>                }</span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> (<span class="dt">Generic</span>)</span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">FromRows</span> <span class="dt">Address</span></span>
<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Store</span> f</span>
<span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkStore</span> {<span class="ot"> storeName    ::</span> <span class="dt">Column</span> f <span class="dt">String</span></span>
<span id="cb21-11"><a href="#cb21-11" aria-hidden="true" tabindex="-1"></a>              ,<span class="ot"> storeAddress ::</span> <span class="dt">Address</span> f</span>
<span id="cb21-12"><a href="#cb21-12" aria-hidden="true" tabindex="-1"></a>              }</span>
<span id="cb21-13"><a href="#cb21-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> (<span class="dt">Generic</span>)</span>
<span id="cb21-14"><a href="#cb21-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">FromRows</span> <span class="dt">Store</span> <span class="co">-- type error</span></span></code></pre></div>
<p>Ideally, we would want this <code>Store</code> type above to be equivalent to:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode haskell literate"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Store</span> f</span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkStore</span> {<span class="ot"> storeName          ::</span> <span class="dt">Column</span> f <span class="dt">String</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>              <span class="co">-- Address gets unpacked into &quot;adjacent&quot; columns</span></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>              ,<span class="ot"> addressCivicNumber ::</span> <span class="dt">Column</span> f <span class="dt">Int</span></span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>              ,<span class="ot"> addressStreetName  ::</span> <span class="dt">Column</span> f <span class="dt">String</span></span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>              }</span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">deriving</span> (<span class="dt">Generic</span>)</span></code></pre></div>
<p>I haven’t figured out how to do this yet, but it would be desirable.</p>
<p><em>This document is a literate Haskell module!</em></p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>R. Lämmel and S. Peyton Jones, <em>Scrap your boilerplate: a practical approach to generic programming</em>. ACM SIGPLAN International Workshop on Types in Language Design and Implementation (2003). <a href="https://www.microsoft.com/en-us/research/publication/scrap-your-boilerplate-a-practical-approach-to-generic-programming">Link</a><a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></summary>
</entry>
<entry>
    <title>Scientific computing with confidence using typed dimensions</title>
    <link href="https://laurentrdc.xyz//posts/typed-dimensions.html" />
    <id>https://laurentrdc.xyz//posts/typed-dimensions.html</id>
    <published>2024-11-20T00:00:00Z</published>
    <updated>2025-02-08</updated>
    <summary type="html"><![CDATA[<p>I have performed non-trivial scientific calculations, in <a href="/about.html">university and beyond</a>, for almost 15 years.</p>
<p>Until the end of undergraduate school, this was mostly done by hand. Optimizing the <a href="https://en.wikipedia.org/wiki/Brachistochrone_curve">trajectory of a heavy ball</a> or solving the <a href="https://en.wikipedia.org/wiki/Heat_equation">heat equation</a> are problems with analytical solutions, and thus can be solved with pen(cil) and paper.</p>
<p>However, there were instances when numerical tools had to be used, rather than analytical ones. This occurred, for example, when replacing models of the physical world with measurements from the physical world in experimental physics classes. By the end of my B.Sc., <a href="/files/ugrad_project.pdf">the need to take measurements, transform them, and report results was made much simpler by using a computer</a>.</p>
<p>Fast forward to graduate school, and the amount of measurements (and their complexity) require the use of some of the most powerful computers I have ever used, even to this day. When implementing numerical routines, I had to pore over the equations (translated to computer expression) countless times, to ensure that they were correctly applied. Most importantly, <strong>all units needed to be carefully checked by hand</strong>. Small mistakes went unnoticed and wasted valuable resources.
Take a look at <a href="https://github.com/LaurentRDC/dissertation/blob/7fb658306b6c7dd1b4c8b983ad5f6d8fb91bcdb1/figures/graphite/eph-coupling.py#L56">one of the computations</a> from my Ph. D. dissertation (<a href="/files/dissertation.pdf">PDF</a>, <a href="https://github.com/LaurentRDC/dissertation">Git repository</a>):</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.constants <span class="im">import</span> physical_constants</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> population(temperature: <span class="bu">float</span>, frequency: <span class="bu">float</span>) <span class="op">-&gt;</span> <span class="bu">float</span>:</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="co">&quot;&quot;&quot;</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="co">    Determine average phonon population at `temperature`.</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="co">    Parameters</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="co">    ----------</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="co">    temperature : float</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="co">        Temperature in Kelvin</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="co">    frequency : float</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="co">        Phonon frequency in Hertz</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="co">    &quot;&quot;&quot;</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    h, <span class="op">*</span>_ <span class="op">=</span> physical_constants[<span class="st">&quot;Planck constant over 2 pi in eV s&quot;</span>]</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>    kb, <span class="op">*</span>_ <span class="op">=</span> physical_constants[<span class="st">&quot;Boltzmann constant in eV/K&quot;</span>]</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="fl">0.5</span> <span class="op">*</span> coth(h <span class="op">*</span> frequency <span class="op">/</span> (<span class="dv">2</span> <span class="op">*</span> kb <span class="op">*</span> temperature)) <span class="op">-</span> <span class="fl">0.5</span></span></code></pre></div>
<p>This isn’t a complex equation, but it showcases the problem perfectly. <code>temperature</code>, <code>frequency</code>, <code>h</code>, and <code>kb</code> are all floating-point numbers, with their units attached <em>as documentation</em>. This is not robust.</p>
<p>These days, instead of meticulously going over the details of calculations ahead of time, I now defer to my computer to check the validity of my calculations <em>as much as possible</em>. That’s why computers exist: to free people from repetitive and error-prone work. In this post, I will describe a mechanism, typed dimensions, by which we can eliminate entire classes of bugs, and how the <a href="https://github.com/bjornbm/dimensional/"><code class="has-text-link">dimensional</code></a> Haskell package makes this easy.</p>
<h2 class="title is-2" id="dimensions-units-and-quantities">Dimensions, units, and quantities</h2>
<p>In the international system of units (also called SI units), there are 7 basic <em>dimensions</em> a physical value can have:</p>
<ul>
<li>time duration <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>T</mi><annotation encoding="application/x-tex">T</annotation></semantics></math>;</li>
<li>length <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>L</mi><annotation encoding="application/x-tex">L</annotation></semantics></math>;</li>
<li>mass <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>M</mi><annotation encoding="application/x-tex">M</annotation></semantics></math>;</li>
<li>electric current <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>I</mi><annotation encoding="application/x-tex">I</annotation></semantics></math>;</li>
<li>thermodynamic temperature <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Θ</mi><annotation encoding="application/x-tex">\Theta</annotation></semantics></math>;</li>
<li>amount of substance <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>N</mi><annotation encoding="application/x-tex">N</annotation></semantics></math>;</li>
<li>luminous intensity <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>J</mi><annotation encoding="application/x-tex">J</annotation></semantics></math>.</li>
</ul>
<p>Using the symbols associated with these base dimensions, we can express any dimension using exponents. For example, velocity (length over time duration) has dimensions <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>L</mi><mi>/</mi><mi>T</mi><mo>=</mo><mi>L</mi><mo>⋅</mo><msup><mi>T</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup></mrow><annotation encoding="application/x-tex">L/T = L \cdot T^{-1}</annotation></semantics></math>, while force (mass-length over time squared) has dimensions <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>M</mi><mo>⋅</mo><mi>L</mi><mo>⋅</mo><msup><mi>T</mi><mrow><mi>−</mi><mn>2</mn></mrow></msup></mrow><annotation encoding="application/x-tex">M \cdot L \cdot T^{-2}</annotation></semantics></math>. Dimensionless quantities have all exponents being 0.</p>
<p>Why are dimensions important? <a href="https://en.wikipedia.org/w/index.php?title=Dimensional_analysis&amp;oldid=1254137729#Mathematical_properties">There are mathematical rules associated with combining numbers with dimensions</a>:</p>
<ul>
<li><p>Two quantities with dimensions <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>D</mi><mn>1</mn></msub><annotation encoding="application/x-tex">D_1</annotation></semantics></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>D</mi><mn>2</mn></msub><annotation encoding="application/x-tex">D_2</annotation></semantics></math> can only be added or subtracted if <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>D</mi><mn>1</mn></msub><mo>≡</mo><msub><mi>D</mi><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">D_1 \equiv D_2</annotation></semantics></math>. For example, it does not make sense to add a length to a mass<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>.</p></li>
<li><p>Any two quantities with dimensions <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>D</mi><mn>1</mn></msub><annotation encoding="application/x-tex">D_1</annotation></semantics></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>D</mi><mn>2</mn></msub><annotation encoding="application/x-tex">D_2</annotation></semantics></math> can be multiplied or divided, in which case the resulting dimension follows the usual rules of arithmetic. For example:</p></li>
</ul>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"><mrow><mo stretchy="true" form="prefix">(</mo><mi>L</mi><mo>⋅</mo><msup><mi>T</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo stretchy="true" form="postfix">)</mo></mrow><mi>/</mi><mrow><mo stretchy="true" form="prefix">(</mo><mi>L</mi><mo>⋅</mo><mi mathvariant="normal">Θ</mi><mo stretchy="true" form="postfix">)</mo></mrow></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><mrow><mo stretchy="true" form="prefix">(</mo><mi>L</mi><mo>⋅</mo><msup><mi>T</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo stretchy="true" form="postfix">)</mo></mrow><mo>⋅</mo><mrow><mo stretchy="true" form="prefix">(</mo><msup><mi>L</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><msup><mi mathvariant="normal">Θ</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo stretchy="true" form="postfix">)</mo></mrow></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><msup><mi>L</mi><mrow><mn>1</mn><mo>−</mo><mn>1</mn></mrow></msup><mo>⋅</mo><msup><mi>T</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><msup><mi mathvariant="normal">Θ</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup></mtd></mtr><mtr><mtd columnalign="right" style="text-align: right; padding-right: 0"></mtd><mtd columnalign="left" style="text-align: left; padding-left: 0"><mo>=</mo><msup><mi>T</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup><mo>⋅</mo><msup><mi mathvariant="normal">Θ</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup></mtd></mtr></mtable><annotation encoding="application/x-tex">
\begin{align}
\left( L \cdot T^{-1} \right) / \left( L \cdot \Theta\right) 
    &amp;= \left( L \cdot T^{-1} \right) \cdot \left( L^{-1} \cdot \Theta^{-1}\right) \\
    &amp;= L^{1 - 1} \cdot T^{-1} \cdot \Theta^{-1} \\
    &amp;= T^{-1} \cdot \Theta^{-1}
\end{align}
</annotation></semantics></math></p>
<p>From these two facts, we can derive some surprising conclusions. For example, the argument to many functions (such as sine, cosine, exponential, etc.) must be dimensionless! Consider the Taylor series expansion of the sine function:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>sin</mi><mo>&#8289;</mo></mrow><mi>x</mi><mo>=</mo><mi>x</mi><mo>−</mo><mfrac><msup><mi>x</mi><mn>3</mn></msup><mrow><mn>3</mn><mi>!</mi></mrow></mfrac><mo>+</mo><mfrac><msup><mi>x</mi><mn>5</mn></msup><mrow><mn>5</mn><mi>!</mi></mrow></mfrac><mo>−</mo><mi>.</mi><mi>.</mi><mi>.</mi></mrow><annotation encoding="application/x-tex">
    \sin{x} = x - \frac{x^3}{3!} + \frac{x^5}{5!} - ...
</annotation></semantics></math></p>
<p>The argument <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math> must have the same dimensions as <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msup><mi>x</mi><mn>3</mn></msup><annotation encoding="application/x-tex">x^3</annotation></semantics></math>, <em>which is only possible if and only if <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>x</mi><annotation encoding="application/x-tex">x</annotation></semantics></math> is a dimensionless quantity</em>.</p>
<p>Units of measure are physical manifestations of dimensions. Dimensions are abstract, while units of measure are concrete. For example, the length dimension <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>L</mi><annotation encoding="application/x-tex">L</annotation></semantics></math> can be measured in units of meters. Each basic dimension has its own canonical unit of measure, the <em>base unit</em>:</p>
<ul>
<li>The second (s) for time duration <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>T</mi><annotation encoding="application/x-tex">T</annotation></semantics></math>;</li>
<li>The meter (m) for length <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>L</mi><annotation encoding="application/x-tex">L</annotation></semantics></math>;</li>
<li>The kilogram (kg) for mass <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>M</mi><annotation encoding="application/x-tex">M</annotation></semantics></math>;</li>
<li>The ampere (A) for electric current <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>I</mi><annotation encoding="application/x-tex">I</annotation></semantics></math>;</li>
<li>The kelvin (K) for thermodynamic temperature <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi mathvariant="normal">Θ</mi><annotation encoding="application/x-tex">\Theta</annotation></semantics></math>;</li>
<li>The mole (mol) for amount of substance <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>N</mi><annotation encoding="application/x-tex">N</annotation></semantics></math>;</li>
<li>The candela (cd) for luminous intensity <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>J</mi><annotation encoding="application/x-tex">J</annotation></semantics></math>.</li>
</ul>
<p>Units for non-basic dimensions, so-called <em>derived units</em>, are combinations of base units using the usual multiplication (<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>⋅</mi><annotation encoding="application/x-tex">\cdot</annotation></semantics></math>) and division (<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>/</mi><annotation encoding="application/x-tex">/</annotation></semantics></math>) operators. For example, velocity has dimensions of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>L</mi><mo>⋅</mo><msup><mi>T</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup></mrow><annotation encoding="application/x-tex">L \cdot T^{-1}</annotation></semantics></math>, and can be measured in units of meters per second (<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mfrac><mi>m</mi><mi>s</mi></mfrac><annotation encoding="application/x-tex">\frac{m}{s}</annotation></semantics></math>). Some derived units have names; for example, the Newton (N) is a derived unit corresponding to <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mfrac><mrow><mtext mathvariant="normal">kg</mtext><mo>⋅</mo><mtext mathvariant="normal">m</mtext></mrow><msup><mtext mathvariant="normal">s</mtext><mn>2</mn></msup></mfrac><annotation encoding="application/x-tex">\frac{\text{kg} \cdot \text{m}}{\text{s}^2}</annotation></semantics></math>.</p>
<p>Based on their dimensions, units can only be combined in certain ways. You can only add/subtract units of the same dimensions, while the multiplication/division of units modifies the dimensions.</p>
<p>Units can be converted to any other units of the same dimensions by conversion <em>base unit</em>. For example, converting from units of imperial feet (ft) to kilometers (km) involves conversion from imperial feet to the base unit of length, the meter, and then conversion from the meter to the kilometer.</p>
<p>Finally, a <em>quantity</em> is a number attached to units. 3.15 meter/second is a quantity with magnitude 3.15, units of meters/second, and dimensions of length over time duration (or <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>L</mi><mo>⋅</mo><msup><mi>T</mi><mrow><mi>−</mi><mn>1</mn></mrow></msup></mrow><annotation encoding="application/x-tex">L \cdot T^{-1}</annotation></semantics></math>).</p>
<p>Scientists take measurements of quantities, and run scientific computations to get answers in the form of other quantities. We can ensure correctness of these computations by realizing that <strong>dimensions are known ahead of time</strong>. This means that for statically- and strongly-typed languages (e.g. Haskell, Rust), we should enforce correctness using the type system.</p>
<h2 class="title is-2" id="type-safe-dimensions">Type-safe dimensions</h2>
<p>People’s first contact with computational unit systems may come from <a href="https://github.com/hgrecco/pint"><code class="has-text-link">pint</code></a>, a Python library to manipulate quantities. While <code>pint</code> is better than nothing, it does not guarantee correctness at runtime due to Python’s dynamic nature.</p>
<p>Instead, I prefer the <a href="https://github.com/bjornbm/dimensional/"><code class="has-text-link">dimensional</code></a> package, a Haskell library created by <a href="https://github.com/bjornbm">Björn Buckwalter</a> that guarantees correctness by ensuring type-safe dimensions at compile-time. Other tools exist for other languages – for example, <a href="https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measure">F# famously includes units of measure</a> as a first-party feature.</p>
<p>We will work by example to compute the <a href="https://en.wikipedia.org/w/index.php?title=Maxwell%E2%80%93Boltzmann_distribution&amp;oldid=1255523817">Maxwell-Boltzmann distribution</a>. This is the distribution of velocities of identical particles of mass <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>m</mi><annotation encoding="application/x-tex">m</annotation></semantics></math>, given some thermodynamic temperature <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>T</mi><annotation encoding="application/x-tex">T</annotation></semantics></math>:</p>
<p><math display="block" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false" form="prefix">(</mo><mi>v</mi><mo stretchy="false" form="postfix">)</mo><mo>=</mo><msup><mrow><mo stretchy="true" form="prefix">(</mo><mfrac><mi>m</mi><mrow><mn>2</mn><mi>π</mi><msub><mi>k</mi><mi>B</mi></msub><mi>T</mi></mrow></mfrac><mo stretchy="true" form="postfix">)</mo></mrow><mfrac><mn>3</mn><mn>2</mn></mfrac></msup><mrow><mi>exp</mi><mo>&#8289;</mo></mrow><mrow><mo stretchy="true" form="prefix">(</mo><mi>−</mi><mfrac><mrow><mi>m</mi><msup><mi>v</mi><mn>2</mn></msup></mrow><mrow><mn>2</mn><msub><mi>k</mi><mi>B</mi></msub><mi>T</mi></mrow></mfrac><mo stretchy="true" form="postfix">)</mo></mrow></mrow><annotation encoding="application/x-tex">
    f(v) = \left( \frac{m}{2 \pi k_B T}\right)^{\frac{3}{2}} \exp{ \left( -\frac{m v^2 }{2 k_B T}\right) }
</annotation></semantics></math></p>
<p>where <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mi>v</mi><annotation encoding="application/x-tex">v</annotation></semantics></math> is the <em>magnitude</em> of particle velocity in a three-dimensional space, and <a href="https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measure"><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><msub><mi>k</mi><mi>B</mi></msub><annotation encoding="application/x-tex">k_B</annotation></semantics></math> is the Boltzmann constant</a>.</p>
<p>Without typed dimensions, the computation of this distribution can be done as follows:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Boltzmann constant in Joules/Kelvin</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ot">boltzmannConstant_JpK ::</span> <span class="dt">Double</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>boltzmannConstant_JpK <span class="ot">=</span> <span class="fl">1.380649e-23</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="ot">untypedMaxwellBoltzmannDist ::</span> <span class="dt">Double</span> <span class="co">-- ^ Particle mass in kilogram</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>                            <span class="ot">-&gt;</span> <span class="dt">Double</span> <span class="co">-- ^ Thermodynamic temperature in Kelvin</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>                            <span class="ot">-&gt;</span> <span class="dt">Double</span> <span class="co">-- ^ Particle velocity in meters/second</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>                            <span class="ot">-&gt;</span> <span class="dt">Double</span> <span class="co">-- ^ Probability density (dimensionless)</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>untypedMaxwellBoltzmannDist mass_kg temp_K velocity_mps </span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> ( mass_kg <span class="op">/</span> (<span class="dv">2</span> <span class="op">*</span> <span class="fu">pi</span> <span class="op">*</span> boltzmannConstant_JpK <span class="op">*</span> temp_K) ) <span class="op">**</span> (<span class="dv">3</span><span class="op">/</span><span class="dv">2</span>) </span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">*</span> <span class="fu">exp</span> ( <span class="op">-</span> (mass_kg <span class="op">*</span> velocity_mps <span class="op">**</span><span class="dv">2</span>) <span class="op">/</span> (<span class="dv">2</span> <span class="op">*</span> <span class="fu">pi</span> <span class="op">*</span> boltzmannConstant_JpK <span class="op">*</span> temp_K) )</span></code></pre></div>
<p>It’s not too hard to check units by hand – but it is tedious and error-prone.</p>
<p>Now let’s do this again, using <a href="https://github.com/bjornbm/dimensional/"><code class="has-text-link">dimensional</code></a>.</p>
<div class="notification is-warning" style="margin-bottom:3cm;margin-top:3cm">
<p>
Dear reader, be forewarned: <b>the rest of this post is not for the faint-of-heart</b>.
</p>
<p>
Yes, this is overkill for simple calculations. And yet, the technique you are about to see has saved me numerous times. There’s quite a bit more ceremony; in exchange, you get a lot more certainty about correctness. Software design is about trade-off, and this level of safety is required for some real-world applications.
</p>
</div>
<p>Setup: I am using the <a href="https://downloads.haskell.org/ghc/9.10.1/docs/users_guide/exts/control.html?highlight=language%20edition#extension-GHC2024">GHC2024 language edition</a>. We will also replace the (implicitly imported) <code>Prelude</code> module to use <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Prelude.html"><code class="has-text-link">Numeric.Units.Dimensional.Prelude</code></a>, which replaces the usual arithmetic operators to use dimension-aware ones, as well as importing the <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Prelude.html#t:Unit"><code class="has-text-link">Unit</code></a>, <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Prelude.html#t:Dimension"><code class="has-text-link">Dimension</code></a>, and <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Prelude.html#t:Quantity"><code class="has-text-link">Quantity</code></a> types.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ot">{-# LANGUAGE NoImplicitPrelude #-}</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Numeric.Units.Dimensional.Prelude</span></span></code></pre></div>
<p>To get acquainted, let’s convert the definition of the Boltzmann constant. The dimensions of the Boltzmann constant are called <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Quantities.html#t:DHeatCapacity"><code class="has-text-link">DHeatCapacity</code></a> in <code>dimensional</code>. Therefore, we can write:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ot">boltzmannConstant ::</span> <span class="dt">Quantity</span> <span class="dt">DHeatCapacity</span> <span class="dt">Double</span></span></code></pre></div>
<p>which means that <code>boltzmannConstant</code> is a <code>Quantity</code> of dimension <code>DHeatCapacity</code>, whose magnitude is represented by a <code>Double</code>. We use the <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Prelude.html#v:-42--126-"><code class="has-text-link">(*~)</code></a> operator to combine a number (<code>1.380649e-23</code>) with a compound unit, <code>joule / kelvin</code>, to get:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ot">boltzmannConstant ::</span> <span class="dt">Quantity</span> <span class="dt">DHeatCapacity</span> <span class="dt">Double</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>boltzmannConstant <span class="ot">=</span> <span class="fl">1.380649e-23</span> <span class="op">*~</span> (joule <span class="op">/</span> kelvin)</span></code></pre></div>
<p>We are not yet ready to implement the Maxwell-Boltzmann distribution function. One particular wrinkle is that exponents (such as the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>3</mn><mi>/</mi><mn>2</mn></mrow><annotation encoding="application/x-tex">3/2</annotation></semantics></math> exponent of the first term) change the dimensions (i.e. the type) of the input. Therefore, some type arithmetic is required. To this end, <code>dimensional</code> provides <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Prelude.html#v:-94-"><code class="has-text-link">(^)</code></a> to raise to an integer power, and <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Prelude.html#v:sqrt"><code class="has-text-link">sqrt</code></a> to take the square root, while appropriately changing the dimensions at compile time. The type signatures are non-trivial to say the least, as it involves compile-time manipulation of types. The operation of “raising to the three-halfs power” becomes:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ot">raiseToThreeHalfsPower ::</span> <span class="dt">Floating</span> a </span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>                       <span class="ot">=&gt;</span> <span class="dt">Quantity</span> d a </span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>                       <span class="ot">-&gt;</span> <span class="dt">Quantity</span> (<span class="dt">NRoot</span> d <span class="dt">Pos2</span> <span class="op">^</span> <span class="dt">Pos3</span>) a</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>raiseToThreeHalfsPower x <span class="ot">=</span> (<span class="fu">sqrt</span> x) <span class="op">^</span> pos3</span></code></pre></div>
<p>where <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Prelude.html#v:pos3"><code class="has-text-link">pos3</code></a> is a type-level integer. The dimension <code>(NRoot d Pos2 ^ Pos3)</code> will resolve to the appropriate dimension at compile-time via <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Prelude.html#t:NRoot">type families</a> once <code>d</code> is known.</p>
<p>Finally, we can implement the (dimensionally-typed) Maxwell-Boltzmann function:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ot">maxwellBoltzmannDist ::</span> <span class="dt">Mass</span> <span class="dt">Double</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>                     <span class="ot">-&gt;</span> <span class="dt">ThermodynamicTemperature</span> <span class="dt">Double</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>                     <span class="ot">-&gt;</span> <span class="dt">Velocity</span> <span class="dt">Double</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>                     <span class="ot">-&gt;</span> <span class="dt">Dimensionless</span> <span class="dt">Double</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>maxwellBoltzmannDist mass temp velocity </span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> raiseToThreeHalfsPower ( mass <span class="op">/</span> (_2 <span class="op">*</span> <span class="fu">pi</span> <span class="op">*</span> boltzmannConstant <span class="op">*</span> temp) )</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">*</span> <span class="fu">exp</span> ( <span class="fu">negate</span> (mass <span class="op">*</span> velocity <span class="op">^</span> pos2) <span class="op">/</span> (_2 <span class="op">*</span> <span class="fu">pi</span> <span class="op">*</span> boltzmannConstant <span class="op">*</span> temp) )</span></code></pre></div>
<p>where <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Prelude.html#v:_2"><code class="has-text-link">_2</code></a> is the dimensionless integer <code>2</code>, and <code>(*)</code>, <code>(/)</code>, <code>exp</code>, <code>negate</code>, and <code>^</code> are all dimensionally-aware operators from <code>dimensional</code> (rather than the <code>Prelude</code> module).</p>
<p>If you compile the program above, you’ll get an error message ಠ_ಠ:</p>
<pre><code>Couldn&#39;t match type ‘Neg3’ with ‘Zero’
  Expected: Dimensionless Double
    Actual: Quantity 
                (NRoot 
                    (DMass 
                        / ((Dim Zero Zero Zero Zero Zero Zero Zero * DHeatCapacity) * DThermodynamicTemperature)) 
                    Pos2 ^ Pos3
                ) 
                Double
(...snip...)</code></pre>
<p>This is because I’m a sloppy physicist – sorry! The Maxwell-Boltzmann distribution <strong>is not a dimensionless quantity</strong>: it actually returns a velocity density with dimensions of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mi>/</mi><mo stretchy="false" form="prefix">(</mo><msup><mi>L</mi><mn>3</mn></msup><mo>⋅</mo><msup><mi>T</mi><mrow><mi>−</mi><mn>3</mn></mrow></msup><mo stretchy="false" form="postfix">)</mo></mrow><annotation encoding="application/x-tex">1 / (L^3 \cdot T^{-3})</annotation></semantics></math>, or <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>L</mi><mrow><mi>−</mi><mn>3</mn></mrow></msup><mo>⋅</mo><msup><mi>T</mi><mn>3</mn></msup></mrow><annotation encoding="application/x-tex">L^{-3} \cdot T^{3}</annotation></semantics></math>.</p>
<p>Let’s fix this. There is no type synonym for velocity density in <code>dimensional</code>, but we can create one ourselves.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">DVelocityCube</span> <span class="ot">=</span> <span class="dt">DVelocity</span> <span class="op">^</span> <span class="dt">Pos3</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">DVelocityDensity</span> <span class="ot">=</span> <span class="dt">Recip</span> <span class="dt">DVelocityCube</span> <span class="co">-- dimension</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">VelocityDensity</span> <span class="ot">=</span> <span class="dt">Quantity</span> <span class="dt">DVelocityDensity</span> <span class="co">-- quantity</span></span></code></pre></div>
<p>Our final version of <code>maxwellBoltzmannDist</code> becomes:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ot">maxwellBoltzmannDist ::</span> <span class="dt">Mass</span> <span class="dt">Double</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>                     <span class="ot">-&gt;</span> <span class="dt">ThermodynamicTemperature</span> <span class="dt">Double</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>                     <span class="ot">-&gt;</span> <span class="dt">Velocity</span> <span class="dt">Double</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>                     <span class="ot">-&gt;</span> <span class="dt">VelocityDensity</span> <span class="dt">Double</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>maxwellBoltzmannDist mass temp velocity </span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> raiseToThreeHalfsPower ( mass <span class="op">/</span> (_2 <span class="op">*</span> <span class="fu">pi</span> <span class="op">*</span> boltzmannConstant <span class="op">*</span> temp) )</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">*</span> <span class="fu">exp</span> ( <span class="fu">negate</span> (mass <span class="op">*</span> velocity <span class="op">^</span> pos2) <span class="op">/</span> (_2 <span class="op">*</span> <span class="fu">pi</span> <span class="op">*</span> boltzmannConstant <span class="op">*</span> temp) )</span></code></pre></div>
<p><a name="interactive-example"></a>
We can compute the result of <code>maxwellBoltzmannDist</code> in any compatible unit. We will do this for a gas of diatomic nitrogen. In an interactive Haskell session:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span> <span class="kw">import</span> <span class="dt">Numeric.Units.Dimensional.NonSI</span> ( unifiedAtomicMassUnit ) <span class="co">-- unifiedAtomicMassUnit = amu</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span> <span class="kw">let</span> n2_mass          <span class="ot">=</span> <span class="dv">2</span>     <span class="op">*~</span> unifiedAtomicMassUnit</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span> <span class="kw">let</span> room_temperature <span class="ot">=</span> <span class="fl">300.0</span> <span class="op">*~</span> kelvin</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span> <span class="kw">let</span> velocity         <span class="ot">=</span> <span class="dv">400</span>   <span class="op">*~</span> (meter <span class="op">/</span> second)</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span> maxwellBoltzmannDist n2_mass room_temperature velocity </span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="fl">4.466578950309018e-11</span> m<span class="op">^-</span><span class="dv">3</span> s<span class="op">^</span><span class="dv">3</span></span></code></pre></div>
<p>We can easily request specific output units using the <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Prelude.html#v:-47--126-"><code class="has-text-link">(/~)</code></a> operator. In this case, we convert result to (hour / nautical mile)<sup>3</sup>:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span> <span class="kw">import</span> <span class="dt">Numeric.Units.Dimensional.NonSI</span> ( nauticalMile, degreeRankine, knot )</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span> <span class="kw">let</span> n2_mass          <span class="ot">=</span> <span class="fl">2.6605E-27</span> <span class="op">*~</span> kilo gram</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span> <span class="kw">let</span> room_temperature <span class="ot">=</span> <span class="fl">491.0</span>      <span class="op">*~</span> degreeRankine</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span> <span class="kw">let</span> velocity         <span class="ot">=</span> <span class="dv">777</span>        <span class="op">*~</span> knot</span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span> (maxwellBoltzmannDist n2_mass room_temperature velocity) <span class="op">/~</span> ((hour <span class="op">/</span> nauticalMile) <span class="op">^</span> pos3)</span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a><span class="fl">5.041390507268275e-12</span></span></code></pre></div>
<h2 class="title is-2" id="design-and-tradeoffs">Design and tradeoffs</h2>
<p><em>This section was added on Nov. 24th, 2024 following discussions on <a href="https://news.ycombinator.com/item?id=42202834">Hacker News</a> and the <a href="https://discourse.haskell.org/t/blog-post-scientific-computing-with-confidence-using-typed-dimensions/10767?u=laurentrdc">Haskell Discourse</a></em></p>
<p>There are many other software packages that support some level of type-safe computational unit systems such as <a href="https://github.com/mpusz/mp-units">mp-units for C++</a>, <a href="https://raku.land/zef:librasteve/Physics::Measure">Physics::Measure and Physics::Unit for Raku</a>, <a href="https://github.com/PainterQubits/Unitful.jl">Unitful for Julia</a>, <a href="https://github.com/hyperjeff/Physical">Physical for Swift</a>, and more. There’s even an entire programming language designed around it called <a href="https://github.com/sharkdp/numbat">Numbat</a>. So what can we learn from <code>dimensional</code>’s design, and importantly, its tradeoffs?</p>
<h4 class="title is-4" id="beyond-checking-to-inference-of-dimensions">Beyond checking to inference of dimensions</h4>
<p>One key feature of <code>dimensional</code> is that it does not only <em>check validity</em>, but also <strong>infers</strong> the dimensions of expressions at compile-time. Take for example, consider the question “What is the type (<code>:t</code>) of 1 meter divided by 1 second?”:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>ghci<span class="op">&gt;</span> <span class="op">:</span>t (<span class="dv">1</span> <span class="op">*~</span> meter) <span class="op">/</span> (<span class="dv">1</span> <span class="op">*~</span> second)</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Quantity</span> (<span class="dt">Dim</span> <span class="dt">Pos1</span> <span class="dt">Zero</span> <span class="dt">Neg1</span> <span class="dt">Zero</span> <span class="dt">Zero</span> <span class="dt">Zero</span> <span class="dt">Zero</span>) <span class="dt">Double</span></span></code></pre></div>
<p>If you read the documentation for <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Prelude.html#t:Dimension"><code class="has-text-link">Dimension</code></a>, you will notice that <code>(Dim Pos1 Zero Neg1 Zero Zero Zero Zero)</code> is the dimension of velocity (also known as <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Quantities.html#t:DVelocity"><code class="has-text-link">DVelocity</code></a>).</p>
<p>This means that the compiler becomes a helpful assistant, rather than simply telling you when you are wrong.</p>
<h4 class="title is-4" id="compile-time-dimensions-runtime-units">Compile-time dimensions, runtime units</h4>
<p>Another key design of <code>dimensional</code> is that the dimensions are typed, but units are runtime values. This has important advantage, but also one major drawback.</p>
<p>The important advantage is flexibility: programs written using <code>dimensional</code> accept a wide variety of inputs whose dimensions are equivalent. Since values’ dimensions are known at compile-time, we can be guaranteed that values will be convertible to base units at runtime. You can see this in <a href="#interactive-example">the usage of <code>maxwellBoltzmannDist</code> above</a>, where I varied the input units without issues, even mixing SI units like <code>kelvin</code> and non-SI units like <code>degreeRankine</code>.</p>
<p>This flexibility comes with a performance cost: each quantity is now composed of two values, the magnitude and the unit, which means that that mathematical operations will be slower. For performance-sensitive code, I recommend validating inputs using <code>dimensional</code>, and converting to raw <code>Double</code> using <a href="https://hackage.haskell.org/package/dimensional-1.6.1/docs/Numeric-Units-Dimensional-Prelude.html#v:-47--126-"><code class="has-text-link">(/~)</code></a> before compute-heavy operations.</p>
<h4 class="title is-4" id="non-extensibility">Non-extensibility</h4>
<p><code>dimensional</code> is limited to the 7 physical dimensions by design. However, other libraries such as <a href="https://hackage.haskell.org/package/units">units</a>, allow the creation of extensible unit systems, not limited to physical dimensions.</p>
<p>The lack of extensibility is not an inherent design choice, but rather an implementation choice. This may change in the future.</p>
<h2 class="title is-2" id="conclusion">Conclusion</h2>
<p>This was a whirlwind tour of <code>dimensional</code> with a practical example. If this was your first introduction to typed dimensions in Haskell, do not be alarmed – I bounced off of it the first time.</p>
<p>As mentioned, software design is about trade-off. Using <code>dimensional</code> is complex, but it isn’t complicated<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>; it makes you address the complexity of dimensions and units up-front, rather than hoping for the best. Sometimes this doesn’t make sense, but for critical calculations, there is nothing like typed dimensions.</p>
<p>I am now a <a href="https://github.com/bjornbm/dimensional/">maintainer of <code>dimensional</code> on GitHub</a>, and <strong>I want nothing more than to help people use typed dimensions</strong> (when it makes sense). If you have any feedback, for example missing features or lacking documentation, <a href="https://github.com/bjornbm/dimensional/issues">feel free to raise an issue</a>!</p>
<p><em>Code available in <a href="/files/typed-dimensions/TypedDimensions/Typed.hs">Haskell module</a>.</em></p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p><a href="https://news.ycombinator.com/item?id=42202834#42213927">As pointed out on Hacker News</a>, this is necessary but not sufficient. For example, intensive dimensions (such as thermodynamic temperature) cannot be meaningfully added together.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p><a href="https://english.stackexchange.com/questions/10459/what-is-the-difference-between-complicated-and-complex">Complexity is inherent, complicatedness is extraneous</a>.<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></summary>
</entry>
<entry>
    <title>Starting a new adventure with Powerweave</title>
    <link href="https://laurentrdc.xyz//posts/powerweave-launch.html" />
    <id>https://laurentrdc.xyz//posts/powerweave-launch.html</id>
    <published>2024-04-05T00:00:00Z</published>
    <updated>2025-02-08</updated>
    <summary type="html"><![CDATA[<p>I co-founded <a href="https://powerweave.io">Powerweave</a> with <a href="https://www.linkedin.com/in/mathilde-mounier-005320170/">Mathilde Mounier</a>. We have been working nights and weekends for the better part of a year. Today, I can reveal it publicly.</p>
<p>Starting a business is something that I have been thinking about since finishing graduate school. <a href="/about.html">My academic expertise</a> could not be turned into a business outright (<a href="https://www.linkedin.com/company/e-ray-scientific-inc/">although ex-colleagues are trying!</a>), but my skills in mathematics, software engineering, and computer science have a broader applicability.</p>
<p>Mathilde and I want to act on the climate emergency. As simple citizens, our actions have a limited effect. However, by starting the right business, we can create a movement which has a tangible impact. I am positively inclined towards technology startups specifically because of the growth curve. This means that if everything goes right, Powerweave could change the world.</p>
<p>For many reasons, including the push towards sustainable energy and the increasing demand for energy due to a resurgence of artificial intelligence progress, power grid infrastructure is under tremendous stress, and technologies are evolving rapidly to address this. The space is fertile ground for innovators that seek to help the world in a concrete way.
In order to get both startup and industry experience, I joined SocïVolta, a technology startup that operates at the intersection of financial markets and the North American power grid. This is also where I met Mathilde. We both gained invaluable insights into how the North American power infrastructure works – and where its weaknesses are.</p>
<p>In this post, I will describe current power infrastructure, how Powerweave helps, and what’s next for us.</p>
<h3 class="title is-3" id="what-is-the-north-american-power-grid">What is the North American power grid?</h3>
<p>The <em>power grid</em> is an electrical network which can be categorized into three broad levels:</p>
<ul>
<li>Generation: power stations, which are often far from population centers;</li>
<li>Transmission: long-distance electrical transmission lines connecting power stations to population centers;</li>
<li>Distribution: network of low-voltage transmission to homes and businesses.</li>
</ul>
<p>There are places in North America where all three levels are controlled by a single entity (e.g. Hydro-Québec). But increasingly, different entities own and operate different levels of the power grid.</p>
<p>What is the provenance of the electricity that powers your screen right now? It might not be from the closest power station. The provenance of your electricity depends on lots of factors, including who else wants electricity right now, and who is currently generating electricity. Sometimes, it is better to use a power source far from you, but that takes a path which is relatively unused.</p>
<p>Most people want cheap electricity. Getting you the cheapest power every second of the year requires <strong>coordination between all operating entities on the power grid</strong>. The modern way to coordinate the behavior of the power grid at all levels are so-called <em>wholesale electricity markets</em>. At wholesale electricity markets, power station owners, transmission line owners, and energy service providers come together to enter auctions to determine the geographical price of electricity. While the details of such auctions are far beyond the scope of this blog post, the important bit is that power auctions answer the following two questions:</p>
<ol type="1">
<li>Where does the energy produced by a power station get consumed?</li>
<li>What is the cost of this energy at every node in the power grid?</li>
</ol>
<p>Wholesale electricity markets have been shown to increase competition and lower electricity rates, as well as integrate renewable energy resources more effectively. That is why you see them popping up more and more across the world. <a href="https://energy.ec.europa.eu/topics/markets-and-consumers/market-legislation/electricity-market-design_en">The European Union even codified it into law in 2019</a>.</p>
<h3 class="title is-3" id="local-electricity-distribution">Local electricity distribution</h3>
<p>Let’s zoom in on the last level, where Powerweave operates: local electricity distribution.</p>
<p>It used to be that local distribution of electricity was squarely in one direction: homes and businesses would only consume electricity. With the advent of rooftop solar panels and home batteries, <strong>this is no longer true</strong>. Homes and businesses can act as spontaneous, small power stations called <em>distributed energy resources</em>.</p>
<p>On one hand, we should encourage individuals and businesses to produce their own energy and even export it back to the grid at certain times. Electricity consumption per capita is increasing rapidly, which is stressing power infrastructure. Individuals and businesses that produce and consume energy, <em>prosumers</em>, invest in power infrastructure so that the utilities don’t have to – a concept known as <em>virtual infrastructure upgrades</em>. The alternative is that energy service providers (e.g. utilities) invest in infrastructure, in which case <em>all rate-payers</em> split the bill.</p>
<p>On the other hand, energy service providers are either not ready, or unwilling, to absorb spontaneous extra energy from prosumers. From an electricity distributor point-of-view, it would be much better for electricity to be consumed close to where it is generated (<em>community self-consumption</em>).</p>
<p>At the local distribution level, what is now needed is <strong>coordination between all rate-payers in a community</strong>. Does this problem remind you of something?</p>
<h3 class="title is-3" id="so-what-is-powerweave">So what is Powerweave?</h3>
<p>Powerweave operates a platform that coordinates all rate-payers in a community. It solves the problem of incentivizing rate-payers to invest in power infrastructure and to be more energy efficient when the power grid needs it the most, while also ensuring community self-consumption.</p>
<p>The Powerweave platform is centered around local <em>power auctions</em>, or <em>local electricity markets</em>. For each community, auctions are conducted at regular intervals (usually 5 minutes). Just like wholesale power markets, each auction covers a period of electricity consumption/generation in the near future:</p>
<p><img src="/images/powerweave-launch/pw-auction-structure.png" class="image" /></p>
<p>The time between an auction ending, and its corresponding billing period starting, is the <em>action period</em>. This is a period during which rate-payers <em>know</em> how much power will cost, but they still have influence over how much power they consume or generate.</p>
<p>I cannot stress enough how the existence of the action period is key to Powerweave. Consider this example.</p>
<blockquote>
<p>I am charging my electric car, which will require quite a bit of power (10kW) over the next 8 hours. I participate in the next power auction, where I bid for 10kW of power. However, when closing the auction, I am only cleared to draw 4kW of solar power from a few neighbors at a reasonable price; the shortfall (6kW) will be covered by my utility at a higher price, since the grid is under stress right now. Knowing this in advance, I can slow down or pause charging my vehicle until I can get a better overall energy price.</p>
</blockquote>
<p>This example is the foundation of Powerweave. As a rate-payer, I minimized my electricity bill and used clean sustainable power. My utility incentivized me to be more energy efficient when it mattered, and it also saved on infrastructure costs. Win-win!</p>
<p>However, as you can imagine, constantly participating in auctions and adjusting power consumption/generation (day and night!) is unrealistic for most people. Therefore, <strong>Powerweave automates all of this</strong>.</p>
<p>On the auction side, Powerweave can trade on behalf of rate-payers. Using statistical and machine-learning models trained on historical consumption and generation data, as well as external data such as weather forecasts, Powerweave can place bids and offers for power to achieve goals set by each rate-payer, such as minimizing energy costs, or minimizing carbon emissions. These models are tireless and self-adjusting; you never need to participate in auctions directly if you don’t want to.</p>
<p>On the pricing response side, Powerweave integrates with third-parties (e.g. smartphone notifications, electric vehicle charging systems, smart thermostats) to automatically adjust your load or generation profile.</p>
<p>Our technology is unique in North America (<a href="https://www.brooklyn.energy/">although related technologies have been trialed in the past</a>). Powerweave can legally operate in about 10 US states (including New York and California), with more states potentially opening up soon. Powerweave probably could not have operated even just 5 years ago. We exist at the edge of regulations; this is a great opportunity to influence US-wide reforms on local energy coordination.</p>
<h3 class="title is-3" id="the-near-future">The near future</h3>
<p>Mathilde and I have completed an early technology demonstration, to show that Powerweave’s offering can indeed be realized. We are using a lot of cool technology, which I hope to share with you soon!</p>
<p>Right now, we are focused on partnering with one energy service provider (utility, community choice aggregation, or independent microgrid) to run a pilot project. This will demonstrate that our technology is beneficial, and give confidence to less-technologically-inclined energy service providers (which are most of them) that Powerweave can help them.</p>
<p>If you can help us connect with decision makers at energy service providers, <a href="mailto:laurent@powerweave.io">I would love to hear from you</a>. Getting the first contact with potential partners is difficult; being introduced by someone else helps tremendously.</p>
<p>We hope to grow the team soon as well. If you are interested in Powerweave’s mission, <a href="https://www.linkedin.com/company/powerweaveinc">be sure to follow us on LinkedIn</a>!</p>]]></summary>
</entry>
<entry>
    <title>Trading strategies with typed features using Haskell and type families</title>
    <link href="https://laurentrdc.xyz//posts/typesafe-tradingstrats.html" />
    <id>https://laurentrdc.xyz//posts/typesafe-tradingstrats.html</id>
    <published>2024-02-04T00:00:00Z</published>
    <updated>2025-11-06</updated>
    <summary type="html"><![CDATA[<p>I work in the business of algorithmic power trading, which is the automated trading of various power-related products in regulated <a href="https://en.wikipedia.org/wiki/Electricity_market">electricity markets</a>. Products include short-term inter-jurisdiction arbitrage, financial transmission rights, and more.</p>
<p>This year, my employer is expanding its trading operations to a new class of products. Since there is no overlap between this new work and our current operations, I got to design a technology stack most suited for the task. This technology stack includes Haskell, most importantly because wrong or unexpected trading decisions can (and have) cost us dearly.</p>
<p>In this blog post, I want to show you the basics of how we designed the framework in which to express trading strategies.</p>
<h2 class="title is-2" id="the-fundamentals-of-trading-strategies">The fundamentals of trading strategies</h2>
<p>The fundamental pieces of trading operations are <em>strategies</em>. In algorithmic trading, strategies are computer programs that decide what to trade, and how to trade it, at any given moment.</p>
<p>Let’s take the example of a simple trading strategy that is only concerned with <a href="https://www.nasdaq.com/market-activity/stocks/aapl">AAPL stock</a>. The current stock price is about 190 USD today; our example strategy is defined thusly:</p>
<ul>
<li>If the AAPL price rises above 200, sell our holdings (if we have any);</li>
<li>If the AAPL price falls below 180, buy 10 shares;</li>
</ul>
<p>In this case, the result of this strategy is some signal to buy or sell AAPL stock. We can run our strategy in a loop:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Control.Monad</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Action</span> <span class="ot">=</span> <span class="dt">Buy</span> <span class="dt">Int</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>            <span class="op">|</span> <span class="dt">Sell</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>            <span class="op">|</span> <span class="dt">Hold</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Price</span> <span class="ot">=</span> <span class="dt">Double</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> Control.Monad.forever <span class="op">$</span> <span class="kw">do</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    aaplPrice <span class="ot">&lt;-</span> fetchMostRecentPrice</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">let</span> action <span class="ot">=</span> myStrategy aaplPrice</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>    executeMarketAction action</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">where</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="ot">        myStrategy ::</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> <span class="dt">Action</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>        myStrategy aapl_price</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>            <span class="op">|</span> aapl_price <span class="op">&gt;</span> <span class="dv">200</span> <span class="ot">=</span> <span class="dt">Sell</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>            <span class="op">|</span> aapl_price <span class="op">&lt;</span> <span class="dv">180</span> <span class="ot">=</span> <span class="dt">Buy</span> <span class="dv">10</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>            <span class="op">|</span> <span class="fu">otherwise</span>        <span class="ot">=</span> <span class="dt">Hold</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a><span class="ot">        fetchMostRecentPrice ::</span> <span class="dt">IO</span> <span class="dt">Price</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>        fetchMostRecentPrice <span class="ot">=</span> (<span class="op">...</span>)</span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a><span class="ot">        executeMarketAction ::</span> <span class="dt">Action</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a>        execureMarketAction <span class="ot">=</span> (<span class="op">...</span>)</span></code></pre></div>
<p>and boom, you have a simple trading system!</p>
<p>Once you have a good idea for a strategy, you should test it on historical data. This is called <em>backtesting</em>. Backtesting strategies is, by definition, much more computationally intensive than live trading, since you are evaluating your strategy on much more data. We often backtest strategies on 5-10 years’ worth of data when it makes sense, and sometimes more.</p>
<p>I will also note that it is easiest to have strategies that can run in various contexts (including backtesting and live operations) if the strategy is <em>pure</em> (in the <a href="https://en.wikipedia.org/w/index.php?title=Pure_function&amp;oldid=1192610707">mathematical sense</a>). It is in the quest for purity and performance that we decided to implement the trading system for a new asset class in Haskell.</p>
<h2 class="title is-2" id="trading-strategies-in-haskell">Trading strategies in Haskell</h2>
<p>For the simplicity of presentation, we will only consider strategies that involve prices. The simplest such strategies are strategies which depend on the <em>most recent</em> price:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Strategy</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkStrategy</span> {<span class="ot"> runStrategy ::</span> <span class="dt">Price</span> <span class="ot">-&gt;</span> <span class="dt">Action</span> }</span></code></pre></div>
<p><code>Strategy</code> is a type of functions, from the most recent <code>Price</code> known to some market action. This is only re-packaging the example above.</p>
<p>Let’s build a backtesting framework. There are two parts here:</p>
<ul>
<li>determine historical market actions;</li>
<li>simulate the effects of market actions.</li>
</ul>
<p>In practice, the two parts of backtesting are handled simultaneously. However, for simplicity, I will only consider the first part here.</p>
<p>The nature of this problem is well-suited to streaming approaches; I will use <a href="https://hackage.haskell.org/package/pipes"><code class="has-text-link">pipes</code></a><a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- From the `time` package</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span>           <span class="dt">Data.Time</span>     ( <span class="dt">UTCTime</span> )</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- From the `pipes` package</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span>           <span class="dt">Pipes</span>         ( <span class="dt">Producer</span>, (&gt;-&gt;) )</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Pipes</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Pipes.Prelude</span> <span class="kw">as</span> <span class="dt">Pipes</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- | From a stream of input features, produce a stream</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- of output &#39;Market&#39; actions</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="ot">backtestStrategy ::</span> <span class="dt">Monad</span> m</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>                 <span class="ot">=&gt;</span> <span class="dt">Strategy</span> r</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>                 <span class="ot">-&gt;</span> <span class="dt">Producer</span> (<span class="dt">UTCTime</span>, <span class="dt">Price</span>)  m () <span class="co">-- ^ stream of timestamped AAPL prices</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>                 <span class="ot">-&gt;</span> m <span class="dt">BacktestResults</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>backtestStrategy strat prices</span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span>   prices</span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;-&gt;</span> Pipes.map (\(k, f) <span class="ot">-&gt;</span> (k, runStrategy strat f))</span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;-&gt;</span> simulateMarketActions</span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a><span class="co">-- The following is out-of-scope</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">BacktestResults</span> <span class="ot">=</span> <span class="dt">MkBacktestResults</span> (<span class="op">...</span>)</span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a><span class="ot">simulateMarketActions ::</span> <span class="dt">Consumer</span> (<span class="dt">UTCTime</span>, <span class="dt">Action</span>) m <span class="dt">BacktestResults</span></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a>simulateMarketActions <span class="ot">=</span> (<span class="op">...</span>)</span></code></pre></div>
<h2 class="title is-2" id="more-expressive-strategies">More expressive strategies</h2>
<p>I have a problem with the above definition of <code>Strategy</code>: I’m limited to strategies based on the single, most recent <code>Price</code>. What if I had a good idea for a strategy which involves the last 10 price values? Our <code>Strategy</code> type is not expressive enough: it only takes one type of <em>feature</em>, while we want to support a wide range of features.</p>
<p>I will define a <code>Strategy</code> type which removes restrictions on the input feature:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Strategy</span> r</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkStrategy</span> {<span class="ot"> runStrategy ::</span> r <span class="ot">-&gt;</span> <span class="dt">Action</span> }</span></code></pre></div>
<p>with the understanding that the data of type <code>r</code> is somehow <em>derived</em> from prices.</p>
<p>What are some features derived from prices, that we might be interested in?</p>
<ul>
<li>Price history, e.g. most recent N ticks;</li>
<li>Price aggregations, e.g. average of most recent M ticks;</li>
<li><a href="/posts/rolling-stats.html">Rolling aggregations</a>, e.g. N-tick history of the averages of M ticks;</li>
</ul>
<p>Every conceptual feature described above has some free parameters. We don’t want to have separate strategies like <code>Strategy PriceHistoryForPast10Ticks</code> and <code>Strategy PriceHistoryForPast20Ticks</code>. More specifically, for every feature of type <code>r</code>, there is a type of parameters <code>p</code> which describes the parameters of <code>r</code>.</p>
<p>For example<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- from the `javelin` package</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Series</span> ( <span class="dt">Series</span> )</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- Feature I may want to use in a strategy</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">PriceHistory</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkPriceHistory</span> (<span class="dt">Series</span> <span class="dt">UTCTime</span> <span class="dt">Price</span>)</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- Parameters that may affect the featyre `PriceHistory`</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">NumTicks</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkNumTicks</span> {<span class="ot"> numTicks ::</span> <span class="dt">Int</span> }</span></code></pre></div>
<h2 class="title is-2" id="typed-features-and-their-parametrization">Typed features and their parametrization</h2>
<p>We could list all possible features in a big sum type:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Feature</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">FPrice</span> <span class="dt">Price</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">FPriceHistory</span> (<span class="dt">Series</span> <span class="dt">UTCTime</span> <span class="dt">Price</span>)</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> <span class="dt">FAveragePrice</span> <span class="dt">Price</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> (<span class="op">...</span>)</span></code></pre></div>
<p>However, it’s rather cumbersome to create a strategy to experiment with new features. We can do better.</p>
<p>We want to be able to link the types <code>PriceHistory</code> and <code>NumTicks</code> such that they are used together when backtesting, to ensure type safety. This is the domain of <a href="https://wiki.haskell.org/GHC/Type_families">indexed type families</a>, or type families for short. We will amend our <code>Feature</code> type to become a typeclass, and upgrade <code>backtestStrategy</code> function to take into account feature parametrization:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Feature</span> r <span class="kw">where</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- For every instance `r` of `Feature`,</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- there is an associated type `Parameters r` which the user</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- needs to specify. See examples below.</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Parameters</span> r</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="ot">    deriveFeature ::</span> <span class="dt">Monad</span> m</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>                  <span class="ot">=&gt;</span> <span class="dt">Parameters</span> r</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>                  <span class="ot">-&gt;</span> <span class="dt">Producer</span> (<span class="dt">UTCTime</span>, <span class="dt">Price</span>) m ()</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>                  <span class="ot">-&gt;</span> <span class="dt">Producer</span> (<span class="dt">UTCTime</span>, r) m ()</span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a><span class="ot">backtestStrategy ::</span> (<span class="dt">Feature</span> r, <span class="dt">Monad</span> m)</span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>                 <span class="ot">=&gt;</span> <span class="dt">Strategy</span> r</span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>                 <span class="ot">-&gt;</span> <span class="dt">Parameters</span> r</span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a>                 <span class="ot">-&gt;</span> <span class="dt">Producer</span> (<span class="dt">UTCTime</span>, <span class="dt">Price</span>)  m ()</span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a>                 <span class="ot">-&gt;</span> m <span class="dt">BacktestResults</span></span>
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a>backtestStrategy strat params prices</span>
<span id="cb7-18"><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span>   deriveFeature params prices</span>
<span id="cb7-19"><a href="#cb7-19" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;-&gt;</span> Pipes.map (\(k, feature) <span class="ot">-&gt;</span> (k, runStrategy strat feature))</span>
<span id="cb7-20"><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;-&gt;</span> simulateMarketActions</span></code></pre></div>
<p>Let’s look at two example instances of <code>Feature</code>. The simplest is the basic feature or <code>Price</code>:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">NoParameters</span> <span class="ot">=</span> ()</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Feature</span> <span class="dt">Price</span> <span class="kw">where</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>    <span class="co">-- The `Price` feature has no free parameters</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Parameters</span> <span class="dt">Price</span> <span class="ot">=</span> <span class="dt">NoParameters</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="ot">    deriveFeature ::</span> <span class="dt">Monad</span> m</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>                  <span class="ot">=&gt;</span> <span class="dt">NoParameters</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>                  <span class="ot">-&gt;</span> <span class="dt">Producer</span> (<span class="dt">UTCTime</span>, <span class="dt">Price</span>) m ()</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>                  <span class="ot">-&gt;</span> <span class="dt">Producer</span> (<span class="dt">UTCTime</span>, <span class="dt">Price</span>) m ()</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>    deriveFeatures _ prices <span class="ot">=</span> prices</span></code></pre></div>
<p>This is easy because there are no parameters. What about looking at the price history?</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">PriceHistory</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkPriceHistory</span> (<span class="dt">Series</span> <span class="dt">UTCTime</span> <span class="dt">Price</span>)</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">NumTicks</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkNumTicks</span> {<span class="ot"> numTicks ::</span> <span class="dt">Int</span> }</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Feature</span> <span class="dt">PriceHistory</span> <span class="kw">where</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Parameters</span> <span class="dt">PriceHistory</span> <span class="ot">=</span> <span class="dt">NumTicks</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a><span class="ot">    deriveFeature ::</span> <span class="dt">Monad</span> m</span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>                  <span class="ot">=&gt;</span> <span class="dt">NumTicks</span></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>                  <span class="ot">-&gt;</span> <span class="dt">Producer</span> (<span class="dt">UTCTime</span>, <span class="dt">Price</span>) m ()</span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>                  <span class="ot">-&gt;</span> <span class="dt">Producer</span> (<span class="dt">UTCTime</span>, <span class="dt">PriceHistory</span>) m ()</span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a>    deriveFeature (<span class="dt">MkPriceHistoryParameters</span> numTicks) prices</span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a>        <span class="ot">=</span> prices <span class="op">&gt;-&gt;</span> accumulate numTicks</span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a>                 <span class="op">&gt;-&gt;</span> Pipes.map (\xs <span class="ot">-&gt;</span> (<span class="fu">maximum</span> <span class="op">$</span> Series.index xs, <span class="dt">MkPriceHistory</span> xs))</span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a>        <span class="kw">where</span></span>
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a>            <span class="co">-- out of scope, see end of blog post for link to source</span></span>
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a><span class="ot">            accumulate ::</span> <span class="dt">Functor</span> m</span>
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a>                       <span class="ot">=&gt;</span> <span class="dt">Int</span></span>
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a>                       <span class="ot">-&gt;</span> <span class="dt">Pipe</span> (<span class="dt">UTCTime</span>, a) (<span class="dt">Series</span> <span class="dt">UTCTime</span> a) m ()</span>
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a>            accumulate <span class="ot">=</span> (<span class="op">...</span>)</span></code></pre></div>
<p>Finally, as an example of the power of this approach, we’ll create a strategy which combines two features.</p>
<p>First, we’ll extend the <code>Feature</code> class to combine two features <code>a</code> and <code>b</code> into one <code>(a, b)</code> feature:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> (<span class="dt">Feature</span> a, <span class="dt">Feature</span> b) <span class="ot">=&gt;</span> <span class="dt">Feature</span> (a, b) <span class="kw">where</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">type</span> <span class="dt">Parameters</span> (a, b) <span class="ot">=</span> (<span class="dt">Parameters</span> a, <span class="dt">Parameters</span> b)</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="ot">    deriveFeature ::</span> <span class="dt">Monad</span> m</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>                  <span class="ot">=&gt;</span> <span class="dt">Parameters</span> (a, b)</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>                  <span class="ot">-&gt;</span> <span class="dt">Producer</span> (<span class="dt">UTCTime</span>, <span class="dt">Price</span>)  m ()</span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>                  <span class="ot">-&gt;</span> <span class="dt">Producer</span> (<span class="dt">UTCTime</span>, (a, b)) m ()</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>    deriveFeature (paramsA, paramsB) prices</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a>        <span class="ot">=</span> Pipes.zipWith (\(k,a) (_, b) <span class="ot">-&gt;</span> (k, (a, b)))</span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>                        (deriveFeature paramsA prices)</span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>                        (deriveFeature paramsB prices)</span></code></pre></div>
<p>Second, we’ll define a simple strategy that compares the most recent price against the average price of the last 10 ticks:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.Series</span> ( fold, mean )</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="ot">finalStrategy ::</span> <span class="dt">Strategy</span> (<span class="dt">PriceHistory</span>, <span class="dt">Price</span>)</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>finalStrategy</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    <span class="ot">=</span> <span class="dt">MkStrategy</span> <span class="op">$</span> \(<span class="dt">MkPriceHistory</span> history, price)</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>        <span class="ot">-&gt;</span> <span class="kw">let</span> avgPrice <span class="ot">=</span> fold mean history</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>            <span class="kw">in</span> <span class="kw">case</span> price <span class="ot">`compare`</span> avgPrice <span class="kw">of</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>                <span class="dt">GT</span> <span class="ot">-&gt;</span> <span class="dt">Sell</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>                <span class="dt">LT</span> <span class="ot">-&gt;</span> <span class="dt">Buy</span> <span class="dv">10</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>                <span class="dt">EQ</span> <span class="ot">-&gt;</span> <span class="dt">Hold</span></span></code></pre></div>
<p>It is trivial to backtest this strategy like so:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ot">backtestFinalStrategy ::</span> <span class="dt">Monad</span> m</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>                      <span class="ot">=&gt;</span> <span class="dt">Producer</span> (<span class="dt">UTCTime</span>, <span class="dt">Price</span>) m ()</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>                      <span class="ot">-&gt;</span> m <span class="dt">BacktestResults</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>backtestFinalStrategy <span class="ot">=</span> backtestStrategy finalStrategy ( <span class="dt">MkNumTicks</span> <span class="dv">10</span>, () )</span></code></pre></div>
<p>and voilà!</p>
<h2 class="title is-2" id="conclusion">Conclusion</h2>
<p>In this post, I have shown you how to define trading strategies with typed feature parametrization, which is a neat use of type families. It takes advantage of the Haskell type system for type safety AND extensibility to easily create new features.</p>
<p><em>All code is available in this <a href="/files/trading-strats/TradingStrats.hs">Haskell module</a>.</em></p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>If you are unfamiliar with <code>pipes</code>, you should check out its <a href="https://hackage.haskell.org/package/pipes-4.3.16/docs/Pipes-Tutorial.html">tutorial</a>.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>We are storing the price history in a <code>Series</code>, which comes from the <a href="https://hackage.haskell.org/package/javelin"><code>javelin</code> package</a> that I created specifically for this work.<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>]]></summary>
</entry>

</feed>
