<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title><![CDATA[Magnus web site]]></title>
<description><![CDATA[Magnus web site]]></description>
<link>https://magnus.therning.org/</link>
<lastBuildDate>Wed, 18 Feb 2026 00:09:47 +0100</lastBuildDate>
<item>
  <title><![CDATA[Switching to project.el]]></title>
  <description><![CDATA[
<p>
I've used <a href="https://github.com/bbatsov/projectile">projectile</a> ever since I created my own Emacs config. I have a vague
memory choosing it because some other package only supported it. (It might have
been <a href="https://emacs-lsp.github.io/lsp-mode/">lsp-mode</a>, but I'm not sure.) Anyway, now that <a href="https://magnus.therning.org/2026-01-19-trying-eglot,-again.html">I'm trying out eglot</a>, <a href="https://magnus.therning.org/2026-01-25-more-on-the-switch-to-eglot.html">again</a>,
I thought I might as well see if I can switch to <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Projects.html">project.el</a>, which is included
in Emacs nowadays.
</p>
<div id="outline-container-org80f0ee9" class="outline-2">
<h2 id="org80f0ee9">A non-VC project marker</h2>
<div class="outline-text-2" id="text-org80f0ee9">
<p>
Projectile allows using a file, <code>.projectile</code>, in the root of a project. This
makes it possible to turn a folder into a project without having to use version
control. It's possible to configure project.el to respect more VC markers than
what's built-in. This can be used to define a non-VC marker.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">setopt</span> project-vc-extra-root-markers '<span class="org-rainbow-delimiters-depth-2">(</span><span class="org-string">".projectile"</span> <span class="org-string">".git"</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
Since I've set <code>vc-handled-backends</code> to <code>nil</code> (the default made VC interfere
with magit, so I turned it off completely) I had to add <code>".git"</code> to make git
repos be recognised as projects too.
</p>
</div>
</div>
<div id="outline-container-org511d0e2" class="outline-2">
<h2 id="org511d0e2">Xref history</h2>
<div class="outline-text-2" id="text-org511d0e2">
<p>
The first thing to solve was that the <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Xref.html">xref</a> stack wasn't per project. Somewhat
disappointingly there only seems to be two options for <code>xref-history-storage</code>
shipped with Emacs
</p>

<dl class="org-dl">
<dt><code>xref-global-history</code></dt><dd>a single global history (the default)</dd>
<dt><code>xref-window-local-history</code></dt><dd>a history per window</dd>
</dl>

<p>
I had the same issue with projectile, and ended up writing my own package for
it. For project.el I settled on using <a href="https://codeberg.org/imarko/xref-project-history.git">xref-project-history</a>.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">use-package</span> xref-project-history
  <span class="org-builtin">:ensure</span> <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-builtin">:type</span> git
           <span class="org-builtin">:repo</span> <span class="org-string">"https://codeberg.org/imarko/xref-project-history.git"</span>
           <span class="org-builtin">:branch</span> <span class="org-string">"master"</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-builtin">:custom</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>xref-history-storage #'xref-project-history<span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>
</div>
</div>
<div id="outline-container-orgbaa0d4d" class="outline-2">
<h2 id="orgbaa0d4d">Jumping between implementation and test</h2>
<div class="outline-text-2" id="text-orgbaa0d4d">
<p>
Projectile has a function for jumping between implementation and test. Not too
surprisingly it's called <code>projectile-toggle-between-implementation-and-test</code>. I
found some old emails in an archive suggesting that project.el might have had
something similar in the past, but if that's the case it's been removed by now.
When searching for a package I came across <a href="https://lists.gnu.org/archive/html/emacs-devel/2022-09/msg00300.html">this email comparing tools for
finding related files</a>. The author mentions two that are included with Emacs
</p>

<dl class="org-dl">
<dt><code>ff-find-other-file</code></dt><dd>part of find-file.el, which a few other functions and
a rather impressive set of settings to customise its behaviour.</dd>
<dt><code>find-sibling-file</code></dt><dd>a newer command, I believe, that also can be
customised.</dd>
</dl>

<p>
So, there are options, but neither of them are made to work nicely with
project.el out of the box. My most complicated use case seems to be in Haskell
projects where modules for implementation and test live in separate (mirrored)
folder hierarchies, e.g.
</p>

<pre class="example" id="org712aefd">
src
└── Sider
    └── Data
        ├── Command.hs
        ├── Pipeline.hs
        └── Resp.hs
test
└── Sider
    └── Data
        ├── CommandSpec.hs
        ├── PipelineSpec.hs
        └── RespSpec.hs

</pre>

<p>
I'm not really sure how I'd configure <code>find-sibling-rules</code>, which are regular
expressions, to deal with folder hierarchies like this. To be honest, I didn't
really see a way of configuring <code>ff-find-other-file</code> at first either. Then I
happened on a post about <a href="https://dev.to/fredericlepied/emacs-how-to-switch-from-modulepy-to-testmodulepy-67k">switching between a module and its tests in Python</a>.
With its help I came up with the following
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span> <span class="org-function-name">mes/setup-hs-ff</span> <span class="org-rainbow-delimiters-depth-2">()</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">when-let*</span> <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-rainbow-delimiters-depth-4">(</span>proj-root <span class="org-rainbow-delimiters-depth-5">(</span>project-root <span class="org-rainbow-delimiters-depth-6">(</span>project-current<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
              <span class="org-rainbow-delimiters-depth-4">(</span>rel-proj-root <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-keyword">-some--&gt;</span> <span class="org-rainbow-delimiters-depth-6">(</span>buffer-file-name<span class="org-rainbow-delimiters-depth-6">)</span>
                               <span class="org-rainbow-delimiters-depth-6">(</span>file-name-directory it<span class="org-rainbow-delimiters-depth-6">)</span>
                               <span class="org-rainbow-delimiters-depth-6">(</span>f-relative proj-root it<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
              <span class="org-rainbow-delimiters-depth-4">(</span>sub-tree <span class="org-rainbow-delimiters-depth-5">(</span>car <span class="org-rainbow-delimiters-depth-6">(</span>f-split <span class="org-rainbow-delimiters-depth-7">(</span>f-relative <span class="org-rainbow-delimiters-depth-8">(</span>buffer-file-name<span class="org-rainbow-delimiters-depth-8">)</span> proj-root<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
              <span class="org-rainbow-delimiters-depth-4">(</span>search-dirs <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-keyword">--&gt;</span> '<span class="org-rainbow-delimiters-depth-6">(</span><span class="org-string">"src"</span> <span class="org-string">"test"</span><span class="org-rainbow-delimiters-depth-6">)</span>
                                <span class="org-rainbow-delimiters-depth-6">(</span>remove sub-tree it<span class="org-rainbow-delimiters-depth-6">)</span>
                                <span class="org-rainbow-delimiters-depth-6">(</span>-map <span class="org-rainbow-delimiters-depth-7">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-8">(</span>p<span class="org-rainbow-delimiters-depth-8">)</span> <span class="org-rainbow-delimiters-depth-8">(</span>f-join proj-root p<span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span> it<span class="org-rainbow-delimiters-depth-6">)</span>
                                <span class="org-rainbow-delimiters-depth-6">(</span>-select #'f-directory? it<span class="org-rainbow-delimiters-depth-6">)</span>
                                <span class="org-rainbow-delimiters-depth-6">(</span>-mapcat <span class="org-rainbow-delimiters-depth-7">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-8">(</span>p<span class="org-rainbow-delimiters-depth-8">)</span> <span class="org-rainbow-delimiters-depth-8">(</span>f-directories p nil t<span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span> it<span class="org-rainbow-delimiters-depth-6">)</span>
                                <span class="org-rainbow-delimiters-depth-6">(</span>-map <span class="org-rainbow-delimiters-depth-7">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-8">(</span>p<span class="org-rainbow-delimiters-depth-8">)</span> <span class="org-rainbow-delimiters-depth-8">(</span>f-relative p proj-root<span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span> it<span class="org-rainbow-delimiters-depth-6">)</span>
                                <span class="org-rainbow-delimiters-depth-6">(</span>-map <span class="org-rainbow-delimiters-depth-7">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-8">(</span>p<span class="org-rainbow-delimiters-depth-8">)</span> <span class="org-rainbow-delimiters-depth-8">(</span>f-join rel-proj-root p<span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span> it<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
    <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">setq-local</span> ff-search-directories search-dirs
                ff-other-file-alist '<span class="org-rainbow-delimiters-depth-4">(</span><span class="org-rainbow-delimiters-depth-5">(</span><span class="org-string">"Spec\\.hs$"</span> <span class="org-rainbow-delimiters-depth-6">(</span><span class="org-string">".hs"</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span>
                                      <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-string">"\\.hs$"</span> <span class="org-rainbow-delimiters-depth-6">(</span><span class="org-string">"Spec.hs"</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
A few things to note
</p>

<ol class="org-ol">
<li>The order of rules in <code>ff-other-file-alist</code> is important, the first match is
chosen.</li>
<li><code>(buffer-file-name)</code> can, and really does, return <code>nil</code> at times, and
<code>file-name-directory</code> doesn't deal with anything but strings.</li>
<li>The entries in <code>ff-search-directories</code> have to be relative to the file in the
current buffer, hence the rather involved <code>varlist</code> in the <code>when-let*</code>
expression.</li>
</ol>

<p>
With this in place I get the following values for <code>ff-search-directories</code>
</p>

<dl class="org-dl">
<dt><code>src/Sider/Data/Command.hs</code></dt><dd><code>("../../../test/Sider" "../../../test/Sider/Data")</code></dd>
<dt><code>test/Sider/Data/CommandSpec.hs</code></dt><dd><code>("../../../src/Sider" "../../../src/Sider/Data")</code></dd>
</dl>

<p>
And <code>ff-find-other-file</code> works beautifully.
</p>
</div>
</div>
<div id="outline-container-orgb8cf766" class="outline-2">
<h2 id="orgb8cf766">Conclusion</h2>
<div class="outline-text-2" id="text-orgb8cf766">
<p>
My setup with project.el now covers everything I used from projectile so I'm
fairly confident I'll be happy keeping it.
</p>
</div>
</div>
<div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-emacs.html">emacs</a> <a href="https://magnus.therning.org/tag-project-el.html">project-el</a> </div>
]]></description>
  <category><![CDATA[emacs]]></category>
  <category><![CDATA[project-el]]></category>
  <link>https://magnus.therning.org/2026-02-18-switching-to-project.el.html</link>
  <guid>https://magnus.therning.org/2026-02-18-switching-to-project.el.html</guid>
  <pubDate>Wed, 18 Feb 2026 00:09:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Using advice to limit lsp-ui-doc nuisance]]></title>
  <description><![CDATA[
<p>
I've switched back to <a href="https://emacs-lsp.github.io/lsp-mode/">lsp-mode</a> temporarily until I've had time to fix a few
things with my <code>eglot</code> setup. Returning prompted me to finally address an
irritating behaviour with <a href="https://emacs-lsp.github.io/lsp-ui/#lsp-ui-doc">lsp-ui-doc</a>.
</p>

<p>
No matter what I set <code>lsp-ui-doc-position</code> to it ends up covering information
that I want to see. While waiting for a <a href="https://github.com/emacs-lsp/lsp-ui/issues/793">fix</a> I decided to work around it. It
seems to me that this is exactly what <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Advising-Functions.html">advice</a> is for.
</p>

<p>
I came up with the following to make sure the frame appears on the half of the
buffer where <code>point</code> isn't.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span> <span class="org-function-name">my-lsp-ui-doc-wrapper</span> <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-type">&amp;rest</span> _<span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">let*</span> <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-rainbow-delimiters-depth-4">(</span>pos-line <span class="org-rainbow-delimiters-depth-5">(</span>- <span class="org-rainbow-delimiters-depth-6">(</span>line-number-at-pos <span class="org-rainbow-delimiters-depth-7">(</span>point<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span>
                      <span class="org-rainbow-delimiters-depth-6">(</span>line-number-at-pos <span class="org-rainbow-delimiters-depth-7">(</span>window-start<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
         <span class="org-rainbow-delimiters-depth-4">(</span>pos <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-keyword">if</span> <span class="org-rainbow-delimiters-depth-6">(</span>&lt;= pos-line <span class="org-rainbow-delimiters-depth-7">(</span>/ <span class="org-rainbow-delimiters-depth-8">(</span>window-body-height<span class="org-rainbow-delimiters-depth-8">)</span> 2<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span>
                  'bottom
                'top<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
    <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">setopt</span> lsp-ui-doc-position pos<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>

<span class="org-rainbow-delimiters-depth-1">(</span>advice-add 'lsp-ui-doc--move-frame <span class="org-builtin">:before</span> #'my-lsp-ui-doc-wrapper<span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>
<div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-emacs.html">emacs</a> <a href="https://magnus.therning.org/tag-lsp-mode.html">lsp-mode</a> </div>
]]></description>
  <category><![CDATA[emacs]]></category>
  <category><![CDATA[lsp-mode]]></category>
  <link>https://magnus.therning.org/2026-02-16-using-advice-to-limit-lsp-ui-doc-nuisance.html</link>
  <guid>https://magnus.therning.org/2026-02-16-using-advice-to-limit-lsp-ui-doc-nuisance.html</guid>
  <pubDate>Mon, 16 Feb 2026 20:10:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[More on the switch to eglot]]></title>
  <description><![CDATA[
<p>
Since the <a href="https://magnus.therning.org/2026-01-19-trying-eglot,-again.html">switching to eglot</a> I've ended up making a few related changes.
</p>
<div id="outline-container-org8cdfce1" class="outline-2">
<h2 id="org8cdfce1">Replacing flycheck with flymake</h2>
<div class="outline-text-2" id="text-org8cdfce1">
<p>
Since <code>eglot</code> it's written to work with other packages in core, which means it
integrates with <a href="https://www.gnu.org/software/emacs/manual/html_mono/flymake.html"><code>flymake</code></a>. The switch comprised
</p>

<ul class="org-ul">
<li>Use <code>:ensure nil</code> to make sure <code>elpaca</code> knows there's nothing to download.</li>
<li>Add a call to <code>flymake-mode</code> to <code>prog-mode-hook</code>.</li>
<li>Define two functions to toggle showing a list of diagnostics for the current
buffer and the project.</li>
<li></li>

<li>Redefine the relevant keybindings.</li>
</ul>

<p>
The two functions for toggling showing diagnostics look like this
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span> <span class="org-function-name">mes/toggle-flymake-buffer-diagnostics</span> <span class="org-rainbow-delimiters-depth-2">()</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">interactive</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">if-let*</span> <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-rainbow-delimiters-depth-4">(</span>window <span class="org-rainbow-delimiters-depth-5">(</span>get-buffer-window <span class="org-rainbow-delimiters-depth-6">(</span>flymake--diagnostics-buffer-name<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
      <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">save-selected-window</span> <span class="org-rainbow-delimiters-depth-4">(</span>quit-window nil window<span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
    <span class="org-rainbow-delimiters-depth-3">(</span>flymake-show-buffer-diagnostics<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>

<span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span> <span class="org-function-name">mes/toggle-flymake-project-diagnostics</span> <span class="org-rainbow-delimiters-depth-2">()</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">interactive</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">if-let*</span> <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-rainbow-delimiters-depth-4">(</span>window <span class="org-rainbow-delimiters-depth-5">(</span>get-buffer-window <span class="org-rainbow-delimiters-depth-6">(</span>flymake--project-diagnostics-buffer <span class="org-rainbow-delimiters-depth-7">(</span>projectile-project-root<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
      <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">save-selected-window</span> <span class="org-rainbow-delimiters-depth-4">(</span>quit-window nil window<span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
    <span class="org-rainbow-delimiters-depth-3">(</span>flymake-show-project-diagnostics<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
And the changed keybindings are
</p>

<table>


<colgroup>
<col  class="org-left">

<col  class="org-left">
</colgroup>
<thead>
<tr>
<th scope="col" class="org-left">flycheck</th>
<th scope="col" class="org-left">flymake</th>
</tr>
</thead>
<tbody>
<tr>
<td class="org-left">flycheck-next-error</td>
<td class="org-left">flymake-goto-next-error</td>
</tr>

<tr>
<td class="org-left">flycheck-previous-error</td>
<td class="org-left">flymake-goto-prev-error</td>
</tr>

<tr>
<td class="org-left">mes/toggle-flycheck-error-list</td>
<td class="org-left">mes/toggle-flymake-buffer-diagnostics</td>
</tr>

<tr>
<td class="org-left">mes/toggle-flycheck-projectile-error-list</td>
<td class="org-left">mes/toggle-flymake-project-diagnostics</td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="outline-container-orgadc4f2e" class="outline-2">
<h2 id="orgadc4f2e">Using <code>with-eval-after-load</code> instead of <code>:after eglot</code></h2>
<div class="outline-text-2" id="text-orgadc4f2e">
<p>
When it comes to <code>use-package</code> I keep on being surprised, and after the switch
to <code>elpaca</code> I've found some new surprises. One of them was that using <code>:after
eglot</code> like this
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">use-package</span> haskell-ng-mode
  <span class="org-builtin">:afer</span> eglot
  <span class="org-builtin">:ensure</span> <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-builtin">:type</span> git
           <span class="org-builtin">:repo</span> <span class="org-string">"git@gitlab.com:magus/haskell-ng-mode.git"</span>
           <span class="org-builtin">:branch</span> <span class="org-string">"main"</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-builtin">:init</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>add-to-list 'major-mode-remap-alist '<span class="org-rainbow-delimiters-depth-3">(</span>haskell-mode . haskell-ng-mode<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>add-to-list 'eglot-server-programs '<span class="org-rainbow-delimiters-depth-3">(</span>haskell-ng-mode <span class="org-string">"haskell-language-server-wrapper"</span> <span class="org-string">"--lsp"</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">setq-default</span> eglot-workspace-configuration
                <span class="org-rainbow-delimiters-depth-3">(</span>plist-put eglot-workspace-configuration
                           <span class="org-builtin">:haskell</span>
                           '<span class="org-rainbow-delimiters-depth-4">(</span><span class="org-builtin">:formattingProvider</span> <span class="org-string">"fourmolu"</span>
                             <span class="org-builtin">:plugin</span> <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-builtin">:stan</span> <span class="org-rainbow-delimiters-depth-6">(</span><span class="org-builtin">:global-on</span> <span class="org-builtin">:json-false</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
  ...
  <span class="org-builtin">:hook</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>haskell-ng-mode . eglot-ensure<span class="org-rainbow-delimiters-depth-2">)</span>
  ...<span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
would delay initialisation until after <code>eglot</code> had been loaded. However, it
turned out that nothing in <code>:init ...</code> seemed to run and upon opening a haskell file
no mode was loaded.
</p>

<p>
After a bit of thinking and tinkering I got it working by removing <code>:after
eglot</code> and using <code>with-eval-after-load</code>
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">use-package</span> haskell-ng-mode
  <span class="org-builtin">:ensure</span> <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-builtin">:type</span> git
           <span class="org-builtin">:repo</span> <span class="org-string">"git@gitlab.com:magus/haskell-ng-mode.git"</span>
           <span class="org-builtin">:branch</span> <span class="org-string">"main"</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-builtin">:init</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>add-to-list 'major-mode-remap-alist '<span class="org-rainbow-delimiters-depth-3">(</span>haskell-mode . haskell-ng-mode<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">with-eval-after-load</span> 'eglot
    <span class="org-rainbow-delimiters-depth-3">(</span>add-to-list 'eglot-server-programs '<span class="org-rainbow-delimiters-depth-4">(</span>haskell-ng-mode <span class="org-string">"haskell-language-server-wrapper"</span> <span class="org-string">"--lsp"</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
    <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">setq-default</span> eglot-workspace-configuration
                  <span class="org-rainbow-delimiters-depth-4">(</span>plist-put eglot-workspace-configuration
                             <span class="org-builtin">:haskell</span>
                             '<span class="org-rainbow-delimiters-depth-5">(</span><span class="org-builtin">:formattingProvider</span> <span class="org-string">"fourmolu"</span>
                               <span class="org-builtin">:plugin</span> <span class="org-rainbow-delimiters-depth-6">(</span><span class="org-builtin">:stan</span> <span class="org-rainbow-delimiters-depth-7">(</span><span class="org-builtin">:global-on</span> <span class="org-builtin">:json-false</span><span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
  ...
  <span class="org-builtin">:hook</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>haskell-ng-mode . eglot-ensure<span class="org-rainbow-delimiters-depth-2">)</span>
  ...<span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
That change worked for haskell, and it seemed to work for python too, but after
a little while I realised that python needed a bit more attention.
</p>
</div>
</div>
<div id="outline-container-orgc610d55" class="outline-2">
<h2 id="orgc610d55">Getting the configuration for Python to work properly</h2>
<div class="outline-text-2" id="text-orgc610d55">
<p>
The python setup looked like this
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">use-package</span> python
  <span class="org-builtin">:init</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>add-to-list 'major-mode-remap-alist '<span class="org-rainbow-delimiters-depth-3">(</span>python-mode . python-ts-mode<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">with-eval-after-load</span> 'eglot
    <span class="org-rainbow-delimiters-depth-3">(</span>assoc-delete-all '<span class="org-rainbow-delimiters-depth-4">(</span>python-mode python-ts-mode<span class="org-rainbow-delimiters-depth-4">)</span> eglot-server-programs<span class="org-rainbow-delimiters-depth-3">)</span>
    <span class="org-rainbow-delimiters-depth-3">(</span>add-to-list 'eglot-server-programs
                 `<span class="org-rainbow-delimiters-depth-4">(</span><span class="org-rainbow-delimiters-depth-5">(</span>python-mode python-ts-mode<span class="org-rainbow-delimiters-depth-5">)</span> . ,<span class="org-rainbow-delimiters-depth-5">(</span>eglot-alternatives
                                                    '<span class="org-rainbow-delimiters-depth-6">(</span><span class="org-rainbow-delimiters-depth-7">(</span><span class="org-string">"rass"</span> <span class="org-string">"python"</span><span class="org-rainbow-delimiters-depth-7">)</span> <span class="org-string">"pylsp"</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
  ...
  <span class="org-builtin">:hook</span> <span class="org-rainbow-delimiters-depth-2">(</span>python-ts-mode . eglot-ensure<span class="org-rainbow-delimiters-depth-2">)</span>
  ...<span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
and it worked all right, but then I visited the package (using <code>elpaca-visit</code>)
and realised that the downloaded package was all of emacs. That's a bit of
overkill, I'd say.
</p>

<p>
However, adding <code>:ensure nil</code> didn't have the expected effect of just using the
version that's in core. Instead the whole configuration seemed to never take
effect and again I was back to the situation where I had to jump to
<code>python-ts-mode</code> manually.
</p>

<p>
The documentation for <code>use-package</code> says that <code>:init</code> is for
</p>

<blockquote>
<p>
Code to run before PACKAGE-NAME has been loaded.
</p>
</blockquote>

<p>
but I'm guessing "before" isn't quite before enough. Then I noticed <code>:preface</code>
with the description
</p>

<blockquote>
<p>
Code to be run before everything except <code>:disabled</code>; this can be used to define
functions for use in <code>:if</code>, or that should be seen by the byte-compiler.
</p>
</blockquote>

<p>
and yes, "before everything" is early enough. The final python configuration
looks like this
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">use-package</span> python
  <span class="org-builtin">:ensure</span> nil
  <span class="org-builtin">:preface</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>add-to-list 'major-mode-remap-alist '<span class="org-rainbow-delimiters-depth-3">(</span>python-mode . python-ts-mode<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-builtin">:init</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">with-eval-after-load</span> 'eglot
    <span class="org-rainbow-delimiters-depth-3">(</span>assoc-delete-all '<span class="org-rainbow-delimiters-depth-4">(</span>python-mode python-ts-mode<span class="org-rainbow-delimiters-depth-4">)</span> eglot-server-programs<span class="org-rainbow-delimiters-depth-3">)</span>
    <span class="org-rainbow-delimiters-depth-3">(</span>add-to-list 'eglot-server-programs
                 `<span class="org-rainbow-delimiters-depth-4">(</span><span class="org-rainbow-delimiters-depth-5">(</span>python-mode python-ts-mode<span class="org-rainbow-delimiters-depth-5">)</span> . ,<span class="org-rainbow-delimiters-depth-5">(</span>eglot-alternatives
                                                    '<span class="org-rainbow-delimiters-depth-6">(</span><span class="org-rainbow-delimiters-depth-7">(</span><span class="org-string">"rass"</span> <span class="org-string">"python"</span><span class="org-rainbow-delimiters-depth-7">)</span> <span class="org-string">"pylsp"</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
  ...
  <span class="org-builtin">:hook</span> <span class="org-rainbow-delimiters-depth-2">(</span>python-ts-mode . eglot-ensure<span class="org-rainbow-delimiters-depth-2">)</span>
  ...<span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>
</div>
</div>
<div id="outline-container-orgc2d0d13" class="outline-2">
<h2 id="orgc2d0d13">Closing remark</h2>
<div class="outline-text-2" id="text-orgc2d0d13">
<p>
I'm still not sure I have the correct intuition about how to use <code>use-package</code>,
but hopefully it's <i>more</i> correct now than before. I have a growing suspicion
that <code>use-package</code> changes behaviour based on the package manager I use. Or
maybe it's just that some package managers make <code>use-package</code> more forgiving of
bad use.
</p>
</div>
</div>
<div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-eglot.html">eglot</a> <a href="https://magnus.therning.org/tag-emacs.html">emacs</a> </div>
]]></description>
  <category><![CDATA[eglot]]></category>
  <category><![CDATA[emacs]]></category>
  <link>https://magnus.therning.org/2026-01-25-more-on-the-switch-to-eglot.html</link>
  <guid>https://magnus.therning.org/2026-01-25-more-on-the-switch-to-eglot.html</guid>
  <pubDate>Sun, 25 Jan 2026 14:18:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Trying eglot, again]]></title>
  <description><![CDATA[
<p>
I've been using <a href="https://emacs-lsp.github.io/lsp-mode/">lsp-mode</a> since I switched to Emacs several years ago. When <a href="https://github.com/joaotavora/eglot">eglot</a>
made into Emacs core I used it very briefly but quickly switched back. Mainly I
found eglot a bit too bare-bones; I liked some of the bells and whistles of
<code>lsp-ui</code>. Fast-forward a few years and I've grown a bit tired of those bells and
whistles. Specifically that it's difficult to make <code>lsp-ui-sideline</code> and
<code>lsp-ui-doc</code> work well together. <code>lsp-ui-sidedline</code> is shown on the right side,
which is good, but combining it with <code>lsp-ui-doc</code> leads to situations where the
popup covers the sideline. What I've done so far is centre the line to bring the
sideline text out. I was playing a little bit with making the setting of
<code>lsp-ui-doc-position</code> change depending on the location of the current position.
It didn't work that well though so I decided to try to find a simpler setup.
Instead of simplifying the setup of <code>lsp-config</code> I thought I'd give <code>eglot</code>
another shot.
</p>
<div id="outline-container-orgb1f7433" class="outline-2">
<h2 id="orgb1f7433">Basic setup</h2>
<div class="outline-text-2" id="text-orgb1f7433">
<p>
I removed the statements pulling in <code>lsp-mode</code>, <code>lsp-ui</code>, and all
language-specific packages like <code>lsp-haskell</code>. Then I added this to configure
<code>eglot</code>
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">use-package</span> eglot
  <span class="org-builtin">:ensure</span> nil
  <span class="org-builtin">:custom</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>eglot-autoshutdown t<span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>eglot-confirm-server-edits '<span class="org-rainbow-delimiters-depth-3">(</span><span class="org-rainbow-delimiters-depth-4">(</span>eglot-rename . nil<span class="org-rainbow-delimiters-depth-4">)</span>
                                <span class="org-rainbow-delimiters-depth-4">(</span>t . diff<span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
The rest was mainly just switching <code>lsp-mode</code> functions for <code>eglot</code> functions.
</p>

<table>


<colgroup>
<col  class="org-left">

<col  class="org-left">
</colgroup>
<thead>
<tr>
<th scope="col" class="org-left">lsp-mode function</th>
<th scope="col" class="org-left">eglot function</th>
</tr>
</thead>
<tbody>
<tr>
<td class="org-left"><code>lsp-deferred</code></td>
<td class="org-left"><code>eglot-ensure</code></td>
</tr>

<tr>
<td class="org-left"><code>lsp-describe-thing-at-point</code></td>
<td class="org-left"><code>eldoc</code></td>
</tr>

<tr>
<td class="org-left"><code>lsp-execute-code-action</code></td>
<td class="org-left"><code>eglot-code-actions</code></td>
</tr>

<tr>
<td class="org-left"><code>lsp-find-type-definition</code></td>
<td class="org-left"><code>eglot-find-typeDefinition</code></td>
</tr>

<tr>
<td class="org-left"><code>lsp-format-buffer</code></td>
<td class="org-left"><code>eglot-format-buffer</code></td>
</tr>

<tr>
<td class="org-left"><code>lsp-format-region</code></td>
<td class="org-left"><code>eglot-format</code></td>
</tr>

<tr>
<td class="org-left"><code>lsp-organize-imports</code></td>
<td class="org-left"><code>eglot-code-action-organize-imports</code></td>
</tr>

<tr>
<td class="org-left"><code>lsp-rename</code></td>
<td class="org-left"><code>eglot-rename</code></td>
</tr>

<tr>
<td class="org-left"><code>lsp-workspace-restart</code></td>
<td class="org-left"><code>eglot-reconnect</code></td>
</tr>

<tr>
<td class="org-left"><code>lsp-workspace-shutdown</code></td>
<td class="org-left"><code>eglot-shutdown</code></td>
</tr>
</tbody>
</table>

<p>
I haven't verified that the list is fully correct yet, but it looks good so far.
</p>

<p>
The one thing I might miss is lenses, and using <code>lsp-avy-lens</code>. However,
everything that I use lenses for can be done using actions, and to be honest I
don't think I'll miss the huge lens texts from missing type annotations in
Haskell.
</p>
</div>
</div>
<div id="outline-container-orgd8ac829" class="outline-2">
<h2 id="orgd8ac829">Configuration</h2>
<div class="outline-text-2" id="text-orgd8ac829">
<p>
One good thing about <code>lsp-mode</code>'s use of language-specific packages is that
configuration of the various servers is performed through functions. This makes
it easy to discover what options are available, though it also means not all
options may be available. In <code>eglot</code> configuration is less organised, I have to
know about the options for each language server and put the options into
<code>eglot-workspace-configuration</code> myself. It's not always easy to track down what
options are available, and I've found no easy way to verify the settings. For
instance, with <code>lsp-mode</code> I configures <a href="https://github.com/haskell/haskell-language-server">HLS</a> like this
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span>lsp-haskell-formatting-provider <span class="org-string">"fourmolu"</span><span class="org-rainbow-delimiters-depth-1">)</span>
<span class="org-rainbow-delimiters-depth-1">(</span>lsp-haskell-plugin-stan-global-on nil<span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
which translates to this for <code>eglot</code>
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">setq-default</span> eglot-workspace-configuration
              <span class="org-rainbow-delimiters-depth-2">(</span>plist-put eglot-workspace-configuration
                         <span class="org-builtin">:haskell</span>
                         '<span class="org-rainbow-delimiters-depth-3">(</span><span class="org-builtin">:formattingProvider</span> <span class="org-string">"fourmolu"</span>
                           <span class="org-builtin">:plugin</span> <span class="org-rainbow-delimiters-depth-4">(</span><span class="org-builtin">:stan</span> <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-builtin">:global-on</span> <span class="org-builtin">:json-false</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
and I can verify that this configuration has taken effect because I know enough
about the Haskell tools.
</p>

<p>
I do some development in Python and I used to configure <a href="https://pypi.org/project/python-lsp-server/">pylsp</a> like this
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span>lsp-pylsp-plugins-mypy-enabled t<span class="org-rainbow-delimiters-depth-1">)</span>
<span class="org-rainbow-delimiters-depth-1">(</span>lsp-pylsp-plugins-ruff-enabled t<span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
which I <i>think</i> translates to this for <code>eglot</code>
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">setq-default</span> eglot-workspace-configuration
              <span class="org-rainbow-delimiters-depth-2">(</span>plist-put eglot-workspace-configuration
                         <span class="org-builtin">:pylsp</span>
                         '<span class="org-rainbow-delimiters-depth-3">(</span><span class="org-builtin">:plugins</span> <span class="org-rainbow-delimiters-depth-4">(</span><span class="org-builtin">:ruff</span> <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-builtin">:enabled</span> t<span class="org-rainbow-delimiters-depth-5">)</span>
                                     <span class="org-builtin">:mypy</span> <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-builtin">:enabled</span> t<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
but I don't know any convenient way of verifying these settings. I'm simply not
familiar enough with the Python tools. I can check the value of
<code>eglot-workspace-configuration</code> by inspecting it or calling
<code>eglot-show-workspace-configuration</code> but is there really no way of asking the
language server for its active configuration?
</p>
</div>
</div>
<div id="outline-container-org3d20108" class="outline-2">
<h2 id="org3d20108">Closing remark</h2>
<div class="outline-text-2" id="text-org3d20108">
<p>
The last time I gave up on <code>eglot</code> very quickly, probably too quickly to be
honest. I made these changes to my configuration over the weekend, so the real
test of <code>eglot</code> starts when I'm back in the office. I have a feeling I'll stick
to it longer this time.
</p>
</div>
</div>
<div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-eglot.html">eglot</a> <a href="https://magnus.therning.org/tag-emacs.html">emacs</a> <a href="https://magnus.therning.org/tag-lsp-mode.html">lsp-mode</a> </div>
]]></description>
  <category><![CDATA[eglot]]></category>
  <category><![CDATA[emacs]]></category>
  <category><![CDATA[lsp-mode]]></category>
  <link>https://magnus.therning.org/2026-01-19-trying-eglot,-again.html</link>
  <guid>https://magnus.therning.org/2026-01-19-trying-eglot,-again.html</guid>
  <pubDate>Mon, 19 Jan 2026 08:00:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Validation of data in a servant server]]></title>
  <description><![CDATA[
<p>
I've been playing around with adding more validation of data received by an HTTP
endpoint in a <a href="https://hackage.haskell.org/package/servant">servant</a> server. Defining a type with a <code>FromJSON</code> instance is very
easy, just derive a <code>Generic</code> instance and it just works. Here's a simple
example
</p>

<div class="org-src-container">
<pre class="src src-haskell"><code><span class="org-keyword">data</span> Person = Person
    { name :: <span class="org-type">Text</span>
    , age :: <span class="org-type">Int</span>
    , occupation :: <span class="org-type">Occupation</span>
    }
    <span class="org-keyword">deriving</span> (Generic, Show)
    <span class="org-keyword">deriving</span> (FromJSON, ToJSON) via <span class="org-type">(Generically Person)</span>

<span class="org-keyword">data</span> Occupation = UnderAge | Student | Unemployed | SelfEmployed | Retired | Occupation <span class="org-type">Text</span>
    <span class="org-keyword">deriving</span> (Eq, Generic, Ord, Show)
    <span class="org-keyword">deriving</span> (FromJSON, ToJSON) via <span class="org-type">(Generically Occupation)</span>
</code></pre>
</div>

<p>
However, the validation is rather limited, basically it's just checking that
each field is present and of the correct type. For the type above I'd like to
enforce some constraints for the combination of <code>age</code> and <code>occupation</code>.
</p>

<p>
The steps I thought of are
</p>

<ol class="org-ol">
<li>Hide the default constructor and define a <a href="https://wiki.haskell.org/Smart_constructors">smart</a> one. (This is the standard
suggestion for placing extra constraints values.)</li>
<li>Manually define the <code>FromJSON</code> instance using the <code>Generic</code> instance to limit
the amount of code and the smart constructor.</li>
</ol>
<div id="outline-container-org8b6637c" class="outline-2">
<h2 id="org8b6637c">The smart constructor</h2>
<div class="outline-text-2" id="text-org8b6637c">
<p>
I give the constructor the result type <code>Either String Person</code> to make sure it
can both be usable in code and when defining <code>parseJSON</code>.
</p>

<div class="org-src-container">
<pre class="src src-haskell"><code><span class="org-function-name">mkPerson</span> :: <span class="org-type">Text</span> <span class="org-operator">-&gt;</span> <span class="org-type">Int</span> <span class="org-operator">-&gt;</span> <span class="org-type">Occupation</span> <span class="org-operator">-&gt;</span> <span class="org-type">Either String Person</span>
<span class="org-function-name">mkPerson</span> name age occupation = <span class="org-keyword">do</span>
    guardE mustBeUnderAge
    guardE notUnderAge
    guardE tooOldToBeStudent
    guardE mustBeRetired
    pure <span class="org-operator">$</span> Person name age occupation
  <span class="org-keyword">where</span>
    <span class="org-function-name">guardE</span> (pred, err) = when pred <span class="org-operator">$</span> Left err
    <span class="org-function-name">mustBeUnderAge</span> = (age <span class="org-operator">&lt;</span> <span class="org-number">8</span> <span class="org-operator">&amp;&amp;</span> occupation <span class="org-operator">&gt;</span> UnderAge, <span class="org-string">"too young for occupation"</span>)
    <span class="org-function-name">notUnderAge</span> = (age <span class="org-operator">&gt;</span> <span class="org-number">15</span> <span class="org-operator">&amp;&amp;</span> occupation <span class="org-operator">==</span> UnderAge, <span class="org-string">"too old to be under age"</span>)
    <span class="org-function-name">tooOldToBeStudent</span> = (age <span class="org-operator">&gt;</span> <span class="org-number">45</span> <span class="org-operator">&amp;&amp;</span> occupation <span class="org-operator">==</span> Student, <span class="org-string">"too old to be a student"</span>)
    <span class="org-function-name">mustBeRetired</span> = (age <span class="org-operator">&gt;</span> <span class="org-number">65</span> <span class="org-operator">&amp;&amp;</span> occupation <span class="org-operator">/=</span> Retired, <span class="org-string">"too old to not be retired"</span>)
</code></pre>
</div>

<p>
Here I'm making use of <code>Either e</code> being a <code>Monad</code> and use <code>when</code> to apply the
constraints and ensure the reason for failure is given to the caller.
</p>
</div>
</div>
<div id="outline-container-org323ebdf" class="outline-2">
<h2 id="org323ebdf">The <code>FromJSON</code> instance</h2>
<div class="outline-text-2" id="text-org323ebdf">
<p>
When defining the instance I take advantage of the <code>Generic</code> instance to make
the implementation short and simple.
</p>

<div class="org-src-container">
<pre class="src src-haskell"><code><span class="org-keyword">instance</span> FromJSON <span class="org-type">Person</span> <span class="org-keyword">where</span>
    <span class="org-function-name">parseJSON</span> v = <span class="org-keyword">do</span>
        Person{name, age, occupation} &lt;- genericParseJSON defaultOptions v
        either fail pure <span class="org-operator">$</span> mkPerson name age occupation
</code></pre>
</div>

<p>
If there are many more fields in the type I'd consider using <a href="https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/record_wildcards.html"><code>RecordWildCards</code></a>.
</p>
</div>
</div>
<div id="outline-container-orgb6bf602" class="outline-2">
<h2 id="orgb6bf602">Conclusion</h2>
<div class="outline-text-2" id="text-orgb6bf602">
<p>
No, it's nothing ground-breaking but I think it's a fairly nice example of how
things can fit together in Haskell.
</p>
</div>
</div>
<div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-haskell.html">haskell</a> <a href="https://magnus.therning.org/tag-servant.html">servant</a> </div>
]]></description>
  <category><![CDATA[haskell]]></category>
  <category><![CDATA[servant]]></category>
  <link>https://magnus.therning.org/2026-01-04-validation-of-data-in-a-servant-server.html</link>
  <guid>https://magnus.therning.org/2026-01-04-validation-of-data-in-a-servant-server.html</guid>
  <pubDate>Sun, 04 Jan 2026 10:58:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Making a theme based on modus]]></title>
  <description><![CDATA[
<p>
In <code>modus-theme</code> 5.0.0 Prot introduced a structured way to build a theme based
on modus. Just a few days ago he released version 5.1.0 with some improvements
in this area.
</p>

<p>
The official documentation of how to <a href="https://protesilaos.com/emacs/modus-themes#h:86eb375b-9be4-43ce-879a-0686a524a63b">build on top of the Modus themes</a> is very
good. It's focused on how to make sure your theme fits in with the rest of the
"modus universe". However, after reading it I still didn't have a good idea of
how to get started with my own theme. In case others feel the same way I thought
I'd write down how I ended up getting started.
</p>

<p>
The resulting theme, <code>modus-catppuccin</code>, can be found <a href="https://gitlab.com/magus/modus-catppuccin">here</a>.
</p>
<div id="outline-container-org4839f2f" class="outline-2">
<h2 id="org4839f2f">A little background</h2>
<div class="outline-text-2" id="text-org4839f2f">
<p>
I read about how to <a href="https://www.rahuljuliato.com/posts/modus-catppuccin">create a catppuccin-mocha theme using modus-vivendi</a> through
modus' mechanism of overrides. On Reddit someone pointed out that Prot had been
working on basing themes on modus and when I checked the state of it he'd just
released version 5.0.0. Since I'm using catppuccin themes for pretty much all
software with a GUI I thought it could be interesting to see if I could make a
modus-based catppuccin theme to replace my use of <a href="https://github.com/catppuccin/emacs"><code>catppuccin-theme</code></a>.
</p>

<p>
I'm writing the rest as if it was a straight and easy journey. It wasn't! I made
a few false starts, each time realising something new about the structure and
starting over with a better idea.
</p>
</div>
</div>
<div id="outline-container-org61bc0bd" class="outline-2">
<h2 id="org61bc0bd">Finding a starting point</h2>
<div class="outline-text-2" id="text-org61bc0bd">
<p>
When reading what Prot had written about <code>modus-themes</code> in general, and about
how to create themes based on it, in particular, I found that he's ported both
<a href="https://github.com/protesilaos/standard-themes"><code>standard-themes</code></a> and <a href="https://github.com/protesilaos/ef-themes"><code>ef-themes</code></a> so they now are based on modus. Instead of
just using them for inspiration I decided that since <code>standard-themes</code> is so
small I might as well use it as my starting point.
</p>
</div>
</div>
<div id="outline-container-org8f0c803" class="outline-2">
<h2 id="org8f0c803">Starting</h2>
<div class="outline-text-2" id="text-org8f0c803">
<p>
I copied all files of <code>standard-themes</code> to an empty git repository, then I
</p>

<ul class="org-ul">
<li>deleted all but one of the theme file</li>
<li>copied the remaining theme file so I had four in total (one for each of the
<a href="https://catppuccin.com/palette/">catppuccin flavours</a>)</li>
<li>renamed constants, variables, and functions so they would match the
theme and its flavours</li>
<li>put the colours into each <code>catppuccin-&lt;flavour&gt;-palette</code></li>
<li>emptied the common palette, <code>modus-catppuccin-common-palette-mappings</code></li>
<li>made sure that my use of <code>modus-themes-theme</code> was reasonable, in particular
the base palette (I based the light flavour on <code>modus-operandi</code> and the three
dark flavours on <code>modus-vivendi</code>)</li>
</ul>

<p>
The result can be seen <a href="https://gitlab.com/magus/modus-catppuccin/-/tree/c86e17d29e0fc8f0d4a6a2e94a475f32037d2851">here</a>.
</p>

<p>
At this point the three theme flavours contained no relevant mappings of their
own, so what I had was in practice <code>modus-operandi</code> under a new name and
<code>modus-vivendi</code> under three new names.
</p>
</div>
</div>
<div id="outline-container-org28309d9" class="outline-2">
<h2 id="org28309d9">Adding mappings for catppuccin</h2>
<div class="outline-text-2" id="text-org28309d9">
<p>
By organising the theme flavours the way outlined above I only need to add
mappings to <code>modus-catppuccin-common-palette-mappings</code> because
</p>

<ol class="org-ol">
<li>each flavour-specific mapping adds its colour palette using the same name
(that's how catppuccin organises its colors too, <a href="https://catppuccin.com/palette/">as seen here</a>)</li>
<li>each flavour-specific mapping is combined with the common one</li>
<li>any missing mapping is picked up by the underlying theme, <code>modus-operandi</code> or
<code>modus-vivendi</code>, so there will be (somewhat) nice colours for everything</li>
</ol>

<p>
I started out with the mappings in the <a href="https://github.com/protesilaos/standard-themes/blob/main/standard-dark-theme.el">dark standard theme</a> but then I realised
that's not the complete list of available mappings and I started looking at the
themes in <code>modus-themes</code> itself.
</p>
</div>
</div>
<div id="outline-container-orgeb19297" class="outline-2">
<h2 id="orgeb19297">Current state of <code>modus-catppuccin</code></h2>
<div class="outline-text-2" id="text-orgeb19297">
<p>
I've so far defined enough mappings to make it look enough like catppuccin for
my use. There are a lot of possible mappings so my plan is to add them over time
and use <a href="https://github.com/catppuccin/emacs"><code>catppuccin-theme</code></a> for inspiration.
</p>
</div>
</div>
<div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-emacs.html">emacs</a> </div>
]]></description>
  <category><![CDATA[emacs]]></category>
  <link>https://magnus.therning.org/2025-11-08-making-a-theme-based-on-modus.html</link>
  <guid>https://magnus.therning.org/2025-11-08-making-a-theme-based-on-modus.html</guid>
  <pubDate>Sat, 08 Nov 2025 09:45:00 +0100</pubDate>
</item>
<item>
  <title><![CDATA[Listing buffers by tab using consult and bufferlo]]></title>
  <description><![CDATA[
<p>
I've gotten into the habit of using tabs, via <code>tab-bar</code>, to organise my buffers
when I have multiple projects open at once. Each project has its own tab.
There's nothing fancy here (yet), I simply open a new tab manually before
opening a new project.
</p>

<p>
A while ago I added <a href="https://github.com/florommel/bufferlo">bufferlo</a> to my config to help with getting <code>consult-buffer</code>
to organise buffers (somewhat) by tab. I copied the configuration from <a href="https://github.com/florommel/bufferlo?tab=readme-ov-file#consult">the
bufferlo README</a> and started using it. It took me a little while to notice that
the behaviour wasn't quite what I wanted. It seemed like one buffer "leaked"
from another tab.
</p>


<figure id="org1786323">
<img src="static/2025-09-16-buffer-leakage.png" alt="2025-09-16-buffer-leakage.png">

<figcaption><span class="figure-number">Figure 1: </span>Example of buffer leakage</figcaption>
</figure>

<p>
In the image above all files in <code>~/.emacs.d</code> should be listed under <i>Other
Buffers</i>, but one has been brought over into the tab for the Sider project.
</p>

<p>
After a bit of experimenting I realised that
</p>

<ol class="org-ol">
<li>the buffer that leaks is the one I'm in when creating the new tab, and</li>
<li>my function for creating a new tab doesn't work the way I thought.</li>
</ol>

<p>
My function for creating a new tab looked like this
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-2">()</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">interactive</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>tab-new<span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>dashboard-open<span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
and it turns out that <code>tab-new</code> shows the current buffer in the new tab which in
turn caused bufferlo to associate it to the wrong tab. From what I can see
there's no way to tell <code>tab-new</code> to open a specific buffer in the newly created
tab. I tried the following
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-2">()</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">interactive</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">with-current-buffer</span> dashboard-buffer-name
    <span class="org-rainbow-delimiters-depth-3">(</span>tab-new<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
hoping that the dashboard would open in the new tab. It didn't, it was still the
active buffer that popped up in the new tab.
</p>

<p>
In the end I resorted to use <code>bufferlo-remove</code> to simply remove the current
buffer from the new tab.
</p>

<div class="org-src-container">
<pre class="src src-emacs-lisp"><code><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-2">()</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">interactive</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>tab-new<span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>bufferlo-remove <span class="org-rainbow-delimiters-depth-3">(</span>current-buffer<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>dashboard-open<span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</code></pre>
</div>

<p>
No more leakage and <code>consult-buffer</code> works like I wanted it to.
</p>
<div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-emacs.html">emacs</a> </div>
]]></description>
  <category><![CDATA[emacs]]></category>
  <link>https://magnus.therning.org/2025-09-16-listing-buffers-by-tab-using-consult-and-bufferlo.html</link>
  <guid>https://magnus.therning.org/2025-09-16-listing-buffers-by-tab-using-consult-and-bufferlo.html</guid>
  <pubDate>Tue, 16 Sep 2025 08:29:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Reading Redis responses]]></title>
  <description><![CDATA[
<p>
When I began experimenting with writing a new Redis client package I decided to
use lazy bytestrings, because:
</p>

<ol class="org-ol">
<li><a href="https://hackage.haskell.org/package/aeson">aeson</a> seems to prefer it &#x2013; the <a href="https://hackage.haskell.org/package/aeson-2.2.3.0/docs/Data-Aeson.html#g:10">main encoding and decoding functions</a> use lazy
byte strings, though there are <a href="https://hackage.haskell.org/package/aeson-2.2.3.0/docs/Data-Aeson.html#g:11">strict variants</a> too.</li>
<li>the <code>Builder</code> type in <a href="https://hackage-content.haskell.org/package/bytestring">bytestring</a> produce lazy bytestrings.</li>
</ol>

<p>
At the time I was happy to see that <a href="https://hackage.haskell.org/package/attoparsec">attoparsec</a> seemed to support strict and lazy
bytestrings equally well.
</p>

<p>
To get on with things I also wrote the simplest function I could come up with
for sending and receiving data over the network &#x2013; I used <code>send</code> and <code>recv</code> from
<a href="https://hackage.haskell.org/package/network-3.2.7.0/docs/Network-Socket-ByteString-Lazy.html">Network.Socket.ByteString.Lazy</a> in <a href="https://hackage.haskell.org/package/network-3.2.7.0">network</a>. The function was really simple
</p>

<div class="org-src-container">
<pre class="src src-haskell"><code><span class="org-keyword">import</span> Network.Socket.ByteString.Lazy <span class="org-keyword">qualified</span> <span class="org-keyword">as</span> SB

<span class="org-function-name">sendCmd</span> :: <span class="org-type">Conn</span> <span class="org-operator">-&gt;</span> <span class="org-type">Command r</span> <span class="org-operator">-&gt;</span> <span class="org-type">IO </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">(</span></span><span class="org-type">Result r</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">)</span></span>
<span class="org-function-name">sendCmd</span> <span class="org-rainbow-delimiters-depth-1">(</span>Conn p<span class="org-rainbow-delimiters-depth-1">)</span> <span class="org-rainbow-delimiters-depth-1">(</span>Command k cmd<span class="org-rainbow-delimiters-depth-1">)</span> = withResource p <span class="org-operator">$</span> \sock <span class="org-operator">-&gt;</span> <span class="org-keyword">do</span>
    _ &lt;- <span class="org-warning">SB.</span>send sock <span class="org-operator">$</span> toWireCmd cmd
    resp &lt;- <span class="org-warning">SB.</span>recv sock <span class="org-number">4096</span>
    <span class="org-keyword">case</span> decode resp <span class="org-keyword">of</span>
        Left err <span class="org-operator">-&gt;</span> pure <span class="org-operator">$</span> Left <span class="org-operator">$</span> RespError <span class="org-string">"decode"</span> <span class="org-rainbow-delimiters-depth-1">(</span><span class="org-warning">TL.</span>pack err<span class="org-rainbow-delimiters-depth-1">)</span>
        Right r <span class="org-operator">-&gt;</span> pure <span class="org-operator">$</span> k <span class="org-operator">&lt;$&gt;</span> fromWireResp cmd r
</code></pre>
</div>

<p>
with <code>decode</code> defined like this
</p>

<div class="org-src-container">
<pre class="src src-haskell"><code><span class="org-function-name">decode</span> :: <span class="org-type">ByteString</span> <span class="org-operator">-&gt;</span> <span class="org-type">Either String Resp</span>
<span class="org-function-name">decode</span> = parseOnly resp
</code></pre>
</div>

<p>
I knew I'd have to revisit this function, it was naïve to believe that a call to
<code>recv</code> would always result in as single complete response. It was however good
enough to get going. When I got to improving <code>sendCmd</code> I was a little surprised
to find that I'd also have to switch to using strict bytestrings in the parser.
</p>
<div id="outline-container-org94fd594" class="outline-2">
<h2 id="org94fd594">Interlude on the Redis serialisation protocol (RESP3)</h2>
<div class="outline-text-2" id="text-org94fd594">
<p>
The Redis protocol has some defining attributes
</p>

<ul class="org-ul">
<li>It's somewhat of a binary protocol. If you stick to keys and values that fall
within the set of ASCII strings, then the protocol is humanly readable and you
can rather easily use <code>netcat</code> or <code>telnet</code> as a client. However, you aren't
limited to storing only readable strings.</li>
<li>It's somewhat of a <a href="https://redis.io/docs/latest/develop/reference/protocol-spec/#request-response-model">request-response protocol</a>. A notable exception is the
<a href="https://redis.io/docs/latest/commands/?group=pubsub">publish-subscribe subset</a>, but it's rather small and I reckon most Redis users
don't use it.</li>
<li>It's somewhat of a type-length-value style protocol. Some of the data types
include their length in bytes, e.g. <span class="underline">bulk strings</span> and <span class="underline">verbatim strings</span>.
Other types include the number of elements, e.g. <span class="underline">arrays</span> and <span class="underline">maps</span>. A large
number of them have no length at all, e.g. <span class="underline">simple strings</span>, <span class="underline">integers</span>, and
<span class="underline">doubles</span>.</li>
</ul>

<p>
I suspect there are good reasons, I gather a lot of it has to do with speed. It
does however cause one issue when writing a client: <i>it's not possible to read a
whole response without parsing it</i>.
</p>
</div>
</div>
<div id="outline-container-orge572c4f" class="outline-2">
<h2 id="orge572c4f">Rewriting <code>sendCmd</code></h2>
<div class="outline-text-2" id="text-orge572c4f">
<p>
With that extra information about the RESP3 protocol the naïve implementation
above falls short in a few ways
</p>

<ul class="org-ul">
<li>The read buffer may contain more than one full message and give the definition
of <code>decode</code> above any remaining bytes are simply dropped.<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup></li>
<li>The read buffer my contain less than one full message and then <code>decode</code> will
return an error.<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup></li>
</ul>

<p>
Surely this must be solvable, because in my mind running the parser results in
one of three things:
</p>

<ol class="org-ol">
<li>Parsing is done and the result is returned, together with any input that
wasn't consumed.</li>
<li>The parsing is not done due to lack of input, this is typically encoded as a
continuation.</li>
<li>The parsing failed so the error is returned, together with input that wasn't
consumed.</li>
</ol>

<p>
So, I started looking in the documentation for the module
<a href="https://hackage.haskell.org/package/attoparsec-0.14.4/docs/Data-Attoparsec-ByteString-Lazy.html">Data.Attoparsec.ByteString.Lazy</a> in <a href="https://hackage.haskell.org/package/attoparsec">attoparsec</a>. I was a little surprised to find
that the <code>Result</code> type lacked a way to feed more input to a parser &#x2013; it only
has two constructors, <code>Done</code> and <code>Fail</code>:
</p>

<div class="org-src-container">
<pre class="src src-haskell"><code><span class="org-keyword">data</span> Result r
    = Fail <span class="org-type">ByteString</span> <span class="org-type"><span class="org-rainbow-delimiters-depth-1">[</span></span><span class="org-type">String</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">]</span></span> <span class="org-type">String</span>
    | Done <span class="org-type">ByteString</span> <span class="org-type">r</span>
</code></pre>
</div>

<p>
I'm guessing the idea is that the function producing the lazy bytestring in the
first place should be able to produce more chunks of data on demand. That's
likely what the lazy variant of <code>recv</code> does, but at the same time it also
requires choosing a maximum length and that doesn't rhyme with RESP3. The lazy
<code>recv</code> isn't quite lazy in the way I needed it to be.
</p>

<p>
When looking at the parser for strict bytestrings I calmed down. This parser
follows what I've learned about parsers (it's not defined <i>exactly</i> like this;
it's parameterised in its input but for the sake of simplicity I show it with
<code>ByteString</code> as input):
</p>

<div class="org-src-container">
<pre class="src src-haskell"><code><span class="org-keyword">data</span> Result r
    = Fail <span class="org-type">ByteString</span> <span class="org-type"><span class="org-rainbow-delimiters-depth-1">[</span></span><span class="org-type">String</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">]</span></span> <span class="org-type">String</span>
    | Partial <span class="org-rainbow-delimiters-depth-1">(</span><span class="org-type">ByteString</span> <span class="org-operator">-&gt;</span> <span class="org-type">Result r</span><span class="org-rainbow-delimiters-depth-1">)</span>
    | Done <span class="org-type">ByteString</span> <span class="org-type">r</span>
</code></pre>
</div>

<p>
Then to my delight I found that there's already a function for handling exactly
my problem
</p>

<div class="org-src-container">
<pre class="src src-haskell"><code><span class="org-function-name">parseWith</span> :: Monad <span class="org-type">m</span> =&gt; <span class="org-type"><span class="org-rainbow-delimiters-depth-1">(</span></span><span class="org-type">m ByteString</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">)</span></span> <span class="org-operator">-&gt;</span> <span class="org-type">Parser a</span> <span class="org-operator">-&gt;</span> <span class="org-type">ByteString</span> <span class="org-operator">-&gt;</span> <span class="org-type">m </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">(</span></span><span class="org-type">Result a</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">)</span></span>
</code></pre>
</div>

<p>
I only needed to rewrite the existing parser to work with strict bytestrings and
work out how to write a function using <code>recv</code> (for strict bytestrings) that
fulfils the requirements to be used as the first argument to <code>parseWith</code>. The
first part wasn't very difficult due to the similarity between <i>attoparsec</i>'s
APIs for lazy and strict bytestrings. The second only had one complication. It
turns out <code>recv</code> is blocking, but of course that doesn't work well with
<code>parseWith</code>. I wrapped it in <code>timeout</code> based on the idea that timing out means
there's no more data and the parser should be given an empty string so it
finishes. I also decided to pass the parser as an argument, so I could use the
same function for receiving responses for individual commands as well as for
pipelines. The full receiving function is
</p>

<div class="org-src-container">
<pre class="src src-haskell"><code><span class="org-keyword">import</span> Data.ByteString <span class="org-keyword">qualified</span> <span class="org-keyword">as</span> BS
<span class="org-keyword">import</span> Data.Text <span class="org-keyword">qualified</span> <span class="org-keyword">as</span> T
<span class="org-keyword">import</span> Network.Socket.ByteString <span class="org-keyword">qualified</span> <span class="org-keyword">as</span> SB

<span class="org-function-name">recvParse</span> :: <span class="org-type">S.Socket</span> <span class="org-operator">-&gt;</span> <span class="org-type">Parser r</span> <span class="org-operator">-&gt;</span> <span class="org-type">IO </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">(</span></span><span class="org-type">Either Text </span><span class="org-type"><span class="org-rainbow-delimiters-depth-2">(</span></span><span class="org-type">BS.ByteString, r</span><span class="org-type"><span class="org-rainbow-delimiters-depth-2">)</span></span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">)</span></span>
<span class="org-function-name">recvParse</span> sock parser = <span class="org-keyword">do</span>
    parseWith receive parser <span class="org-warning">BS.</span>empty <span class="org-operator">&gt;&gt;=</span> \<span class="org-keyword">case</span>
        Fail _ <span class="org-rainbow-delimiters-depth-1">[]</span> err <span class="org-operator">-&gt;</span> pure <span class="org-operator">$</span> Left <span class="org-rainbow-delimiters-depth-1">(</span><span class="org-warning">T.</span>pack err<span class="org-rainbow-delimiters-depth-1">)</span>
        Fail _ ctxs err <span class="org-operator">-&gt;</span> pure <span class="org-operator">$</span> Left <span class="org-operator">$</span> <span class="org-warning">T.</span>intercalate <span class="org-string">" &gt; "</span> <span class="org-rainbow-delimiters-depth-1">(</span><span class="org-warning">T.</span>pack <span class="org-operator">&lt;$&gt;</span> ctxs<span class="org-rainbow-delimiters-depth-1">)</span> <span class="org-operator">&lt;&gt;</span> <span class="org-string">": "</span> <span class="org-operator">&lt;&gt;</span> <span class="org-warning">T.</span>pack err
        Partial _ <span class="org-operator">-&gt;</span> pure <span class="org-operator">$</span> Left <span class="org-string">"impossible error"</span>
        Done rem result <span class="org-operator">-&gt;</span> pure <span class="org-operator">$</span> Right <span class="org-rainbow-delimiters-depth-1">(</span>rem, result<span class="org-rainbow-delimiters-depth-1">)</span>
  <span class="org-keyword">where</span>
    <span class="org-function-name">receive</span> =
        timeout <span class="org-number">100_000</span> <span class="org-rainbow-delimiters-depth-1">(</span><span class="org-warning">SB.</span>recv sock <span class="org-number">4096</span><span class="org-rainbow-delimiters-depth-1">)</span> <span class="org-operator">&gt;&gt;=</span> \<span class="org-keyword">case</span>
            Nothing <span class="org-operator">-&gt;</span> pure <span class="org-warning">BS.</span>empty
            Just bs <span class="org-operator">-&gt;</span> pure bs
</code></pre>
</div>

<p>
Then I only needed to rewrite <code>sendCmd</code> and I wanted to do it in such a way that
any remaining input data could be use in by the next call to <code>sendCmd</code>.<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup> I
settled for modifying the <code>Conn</code> type to hold an <code>IORef ByteString</code> together
with the socket and then the function ended up looking like this
</p>

<div class="org-src-container">
<pre class="src src-haskell"><code><span class="org-function-name">sendCmd</span> :: <span class="org-type">Conn</span> <span class="org-operator">-&gt;</span> <span class="org-type">Command r</span> <span class="org-operator">-&gt;</span> <span class="org-type">IO </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">(</span></span><span class="org-type">Result r</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">)</span></span>
<span class="org-function-name">sendCmd</span> <span class="org-rainbow-delimiters-depth-1">(</span>Conn p<span class="org-rainbow-delimiters-depth-1">)</span> <span class="org-rainbow-delimiters-depth-1">(</span>Command k cmd<span class="org-rainbow-delimiters-depth-1">)</span> = withResource p <span class="org-operator">$</span> \(sock, remRef<span class="org-rainbow-delimiters-unmatched">)</span> <span class="org-operator">-&gt;</span> <span class="org-keyword">do</span>
    _ &lt;- <span class="org-warning">SBL.</span>send sock <span class="org-operator">$</span> toWireCmd cmd
    rem &lt;- readIORef remRef
    recvParse sock rem resp <span class="org-operator">&gt;&gt;=</span> \<span class="org-keyword">case</span>
        Left err <span class="org-operator">-&gt;</span> pure <span class="org-operator">$</span> Left <span class="org-operator">$</span> RespError <span class="org-string">"recv/parse"</span> err
        Right <span class="org-rainbow-delimiters-unmatched">(</span>newRem, r<span class="org-rainbow-delimiters-unmatched">)</span> <span class="org-operator">-&gt;</span> <span class="org-keyword">do</span>
            writeIORef remRef newRem
            pure <span class="org-operator">$</span> k <span class="org-operator">&lt;$&gt;</span> fromWireResp cmd r
</code></pre>
</div>
</div>
</div>
<div id="outline-container-org83c453b" class="outline-2">
<h2 id="org83c453b">What's next?</h2>
<div class="outline-text-2" id="text-org83c453b">
<p>
I've started looking into pub/sub, and basically all of the work described in
this post is a prerequisite for that. It's not very difficult on the protocol
level, but I think it's difficult to come up with a design that allows maximal
flexibility. I'm not even sure it's worthwhile the complexity.
</p>
</div>
</div>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
This isn't that much of a problem when sticking to the request-response
commands, I think. It most certainly becomes a problem with pub/sub though.
</p></div></div>

<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2" role="doc-backlink">2</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
I'm sure that whatever size of buffer I choose to use there'll be someone
out there who's storing values that are larger. Then there's pipelining that
makes it even more of an issue.
</p></div></div>

<div class="footdef"><sup><a id="fn.3" class="footnum" href="#fnr.3" role="doc-backlink">3</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
To be honest I'm not totally convinced there'll ever be any remaining input.
Unless a single <code>Conn</code> is used by several threads &#x2013; which would lead to much
pain with the current implementation &#x2013; or pub/sub is used &#x2013; which isn't
supported yet.
</p></div></div>


</div>
</div><div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-haskell.html">haskell</a> <a href="https://magnus.therning.org/tag-redis.html">redis</a> </div>
]]></description>
  <category><![CDATA[haskell]]></category>
  <category><![CDATA[redis]]></category>
  <link>https://magnus.therning.org/2025-06-28-reading-redis-responses.html</link>
  <guid>https://magnus.therning.org/2025-06-28-reading-redis-responses.html</guid>
  <pubDate>Sat, 28 Jun 2025 12:41:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Finding a type for Redis commands]]></title>
  <description><![CDATA[
<p>
Arriving at a type for Redis commands required a bit of exploration. I had some
ideas early on that I for various reasons ended up dropping on the way. This is
a post about my travels, hopefully someone finds it worthwhile reading.
</p>
<div id="outline-container-org9e7139e" class="outline-2">
<h2 id="org9e7139e">The protocol</h2>
<div class="outline-text-2" id="text-org9e7139e">
<p>
The <a href="https://redis.io/docs/latest/develop/reference/protocol-spec/">Redis Serialization Protocol</a> (RESP) initially reminded me of JSON and I
thought that following the pattern of <a href="https://hackage.haskell.org/package/aeson">aeson</a> might be a good idea. I decided
up-front that I'd only support the latest version of RESP, i.e. version 3. So, I
thought of a data type, <code>Resp</code> with a constructor for each RESP3 data type, and
a pair of type classes, <code>FromResp</code> and <code>ToResp</code> for converting between Haskell
types and RESP3. Then after some more reflection I realised that converting to
RESP is largely pointless. The main reason to convert anything <i>to</i> RESP3 is to
assemble a command, with its arguments, to send to Redis, but all commands are
<a href="https://redis.io/docs/latest/develop/reference/protocol-spec/#arrays">arrays</a> of <a href="https://redis.io/docs/latest/develop/reference/protocol-spec/#bulk-strings">bulk strings</a> so it's unlikely that anyone will actually use
<code>ToResp</code>.<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup> So I scrapped the idea of <code>ToResp</code>. <code>FromResp</code> looked like this
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-keyword">class</span> FromResp a <span class="org-keyword">where</span>
    <span class="org-function-name">fromResp</span> :: <span class="org-type">Value</span> <span class="org-operator">-&gt;</span> <span class="org-type">Either FromRespError a</span>
</pre>
</div>

<p>
When I started defining commands I didn't like the number of <code>ByteString</code>
arguments that resulted in, so I defined a data type, <code>Arg</code>, and an accompanying
type class for arguments, <code>ToArg</code>:
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-keyword">newtype</span> Arg = Arg <span class="org-rainbow-delimiters-depth-1">{</span>unArg :: <span class="org-type"><span class="org-rainbow-delimiters-depth-2">[</span></span><span class="org-type">ByteString</span><span class="org-type"><span class="org-rainbow-delimiters-depth-2">]</span></span><span class="org-rainbow-delimiters-depth-1">}</span>
    <span class="org-keyword">deriving</span> <span class="org-rainbow-delimiters-depth-1">(</span>Show, Semigroup, Monoid<span class="org-rainbow-delimiters-depth-1">)</span>

<span class="org-keyword">class</span> ToArg a <span class="org-keyword">where</span>
    <span class="org-function-name">toArg</span> :: <span class="org-type">a</span> <span class="org-operator">-&gt;</span> <span class="org-type">Arg</span>
</pre>
</div>

<p>
Later on I saw that it might also be nice to have a type class specifically for
keys, <code>ToKey</code>, though that's a wrapper for a single <code>ByteString</code>.
</p>

<p>
Implementing the functions to encode/decode the protocol were straight-forward
applications of <a href="https://hackage.haskell.org/package/attoparsec">attoparsec</a> and <a href="https://hackage.haskell.org/package/bytestring">bytestring</a> (using its <code>Builder</code>).
</p>
</div>
</div>
<div id="outline-container-org597492d" class="outline-2">
<h2 id="org597492d">A command is a function in need of a sender</h2>
<div class="outline-text-2" id="text-org597492d">
<p>
Even though supporting <a href="https://redis.io/docs/latest/develop/use/pipelining/">pipelining</a> was one of the goals I felt a need to make
sure I'd understood the protocol so I started off with single commands. The
protocol is a simple request/response protocol at the core so I settled on this
type for commands
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-keyword">type</span> Cmd a = forall m. <span class="org-rainbow-delimiters-depth-1">(</span>Monad <span class="org-type">m</span><span class="org-rainbow-delimiters-depth-1">)</span> =&gt; <span class="org-rainbow-delimiters-depth-1">(</span><span class="org-type">ByteString</span> <span class="org-operator">-&gt;</span> <span class="org-type">m ByteString</span><span class="org-rainbow-delimiters-depth-1">)</span> <span class="org-operator">-&gt;</span> <span class="org-type">m </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">(</span></span><span class="org-type">Either FromRespError a</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">)</span></span>
</pre>
</div>

<p>
that is, a command is a function accepting a <i>sender</i> and returning an <i>a</i>.
</p>

<p>
I wrote a helper function for defining commands, <code>sendCmd</code>
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-function-name">sendCmd</span> :: <span class="org-rainbow-delimiters-depth-1">(</span>Monad <span class="org-type">m</span>, FromResp <span class="org-type">a</span><span class="org-rainbow-delimiters-depth-1">)</span> =&gt; <span class="org-type"><span class="org-rainbow-delimiters-depth-1">[</span></span><span class="org-type">ByteString</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">]</span></span> <span class="org-operator">-&gt;</span> <span class="org-rainbow-delimiters-depth-1">(</span><span class="org-type">ByteString</span> <span class="org-operator">-&gt;</span> <span class="org-type">m ByteString</span><span class="org-rainbow-delimiters-depth-1">)</span> <span class="org-operator">-&gt;</span> <span class="org-type">m </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">(</span></span><span class="org-type">Either FromRespError a</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">)</span></span>
<span class="org-function-name">sendCmd</span> cmdArgs send = <span class="org-keyword">do</span>
    <span class="org-keyword">let</span> <span class="org-function-name">cmd</span> = encode <span class="org-operator">$</span> Array <span class="org-operator">$</span> map BulkString cmdArgs
    send cmd <span class="org-operator">&lt;&amp;&gt;</span> decode <span class="org-operator">&gt;&gt;=</span> \<span class="org-keyword">case</span>
        Left desc <span class="org-operator">-&gt;</span> pure <span class="org-operator">$</span> Left <span class="org-operator">$</span> FromRespError <span class="org-string">"Decode"</span> <span class="org-rainbow-delimiters-depth-1">(</span><span class="org-warning">Text.</span>pack desc<span class="org-rainbow-delimiters-depth-1">)</span>
        Right v <span class="org-operator">-&gt;</span> pure <span class="org-operator">$</span> fromValue v
</pre>
</div>

<p>
which made it easy to define commands. Here are two examples, <a href="https://redis.io/docs/latest/commands/append/">append</a> and <a href="https://redis.io/docs/latest/commands/mget/">mget</a>:
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-function-name">append</span> :: <span class="org-rainbow-delimiters-depth-1">(</span>ToArg <span class="org-type">a</span>, ToArg <span class="org-type">b</span><span class="org-rainbow-delimiters-depth-1">)</span> =&gt; <span class="org-type">a</span> <span class="org-operator">-&gt;</span> <span class="org-type">b</span> <span class="org-operator">-&gt;</span> <span class="org-type">Cmd Int</span>
<span class="org-function-name">append</span> key val = sendCmd <span class="org-operator">$</span> <span class="org-rainbow-delimiters-depth-1">[</span><span class="org-string">"APPEND"</span><span class="org-rainbow-delimiters-depth-1">]</span> <span class="org-operator">&lt;&gt;</span> unArg <span class="org-rainbow-delimiters-depth-1">(</span>toArg key <span class="org-operator">&lt;&gt;</span> toArg val<span class="org-rainbow-delimiters-depth-1">)</span>

<span class="org-doc">-- | https://redis.io/docs/latest/commands/mget/</span>
<span class="org-function-name">mget</span> :: <span class="org-rainbow-delimiters-depth-1">(</span>ToArg <span class="org-type">a</span>, FromResp <span class="org-type">b</span><span class="org-rainbow-delimiters-depth-1">)</span> =&gt; <span class="org-type">NE.NonEmpty a</span> <span class="org-operator">-&gt;</span> <span class="org-type">Cmd </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">(</span></span><span class="org-type">NE.NonEmpty b</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">)</span></span>
<span class="org-function-name">mget</span> ks = sendCmd <span class="org-operator">$</span> <span class="org-rainbow-delimiters-depth-1">[</span><span class="org-string">"MGET"</span><span class="org-rainbow-delimiters-depth-1">]</span> <span class="org-operator">&lt;&gt;</span> unArg <span class="org-rainbow-delimiters-depth-1">(</span>foldMap1 toArg ks<span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>

<p>
The function to send off a command and receive its response, <code>sendAndRecieve</code>,
was just a call to <code>send</code> followed by a call to <code>recv</code> in <a href="https://hackage.haskell.org/package/network">network</a> (the variants
for lazy bytestrings).
</p>

<p>
I sort of liked this representation &#x2013; there's always something pleasant with
finding a way to represent something as a function. There's a very big problem
with it though: it's difficult to implement pipelining!
</p>

<p>
Yes, <code>Cmd</code> is a functor since <code>(-&gt;) r</code> is a functor, and thus it's possible to
make it an <code>Applicative</code>, e.g. using <a href="https://hackage.haskell.org/package/free">free</a>. However, to implement pipelining it's
necessary to
</p>

<ol class="org-ol">
<li>encode all commands, then</li>
<li>concatenate them all into a single bytestring and send it</li>
<li>read the response, which is a concatenation of the individual commands'
responses, and</li>
<li>convert each separate response from RESP3.</li>
</ol>

<p>
That isn't easy when each command contains its own encoding and decoding. The
sender function would have to relinquish control after encoding the command, and
resume with the resume again later to decode it. I suspect it's doable using
continuations, or <a href="https://hackage.haskell.org/package/monad-coroutine">monad-coroutine</a>, but it felt complicated and rather than
travelling down that road I asked for ideas on the <a href="https://discourse.haskell.org/t/applicative-that-would-require-two-passes-to-run/12179">Haskell Discourse</a>. The
replies lead me to a paper, <a href="https://www.cs.ox.ac.uk/jeremy.gibbons/publications/delivery.pdf">Free delivery</a>, and a bit later a package,
<a href="https://hackage.haskell.org/package/monad-batcher">monad-batcher</a>. When I got the pointer to the package I'd already read the paper
and started implementing the ideas in it, so I decided to save exploring
<i>monad-batcher</i> for later.
</p>
</div>
</div>
<div id="outline-container-org02d7470" class="outline-2">
<h2 id="org02d7470">A command for free delivery</h2>
<div class="outline-text-2" id="text-org02d7470">
<p>
The paper Free delivery is a perfect match for pipelining in Redis, and my
understanding is that it proposes a solution where
</p>

<ol class="org-ol">
<li>Commands are defined as a GADT, <code>Command a</code>.</li>
<li>Two functions are defined to serialise and deserialise a <code>Command a</code>. In the
paper they use <code>String</code> as the serialisation, so <code>show</code> and <code>read</code> is used.</li>
<li>A type, <code>ActionA a</code>, is defined that combines a command with a modification
of its <code>a</code> result. It implements <code>Functor</code>.</li>
<li>A free type, <code>FreeA f a</code> is defined, and made into an <code>Applicative</code> with the
constraint that <code>f</code> is a <code>Functor</code>.</li>
<li>A function, <code>serializeA</code>, is defined that traverses a <code>FreeA ActionA a</code>
serialising each command.</li>
<li>A function, <code>deserializeA</code>, is defined that traverses a <code>FreeA ActionA a</code>
deserialising the response for each command.</li>
</ol>

<p>
I defined a command type, <code>Command a</code>, with only three commands in it, <code>echo</code>,
<code>hello</code>, and <code>ping</code>. I then followed the recipe above to verify that I could get
it working at all. The Haskell used in the paper is showing its age, and there
seems to be a <code>Functor</code> instance missing, but it was still straight forward and
I could verify that it worked against a locally running Redis.
</p>

<p>
Then I made a few changes&#x2026;
</p>

<p>
I renamed the command type to <code>Cmd</code> so I could use <code>Command</code> for what the
paper calls <code>ActionA</code>.
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-keyword">data</span> Cmd r <span class="org-keyword">where</span>
    Echo :: <span class="org-type">Text</span> <span class="org-operator">-&gt;</span> <span class="org-type">Cmd Text</span>
    Hello :: <span class="org-type">Maybe Int</span> <span class="org-operator">-&gt;</span> <span class="org-type">Cmd </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">()</span></span>
    Ping :: <span class="org-type">Maybe Text</span> <span class="org-operator">-&gt;</span> <span class="org-type">Cmd Text</span>

<span class="org-keyword">data</span> Command a = forall r. Command !<span class="org-rainbow-delimiters-depth-1">(</span><span class="org-type">r</span> <span class="org-operator">-&gt;</span> <span class="org-type">a</span><span class="org-rainbow-delimiters-depth-1">)</span> !<span class="org-type"><span class="org-rainbow-delimiters-depth-1">(</span></span><span class="org-type">Cmd r</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">)</span></span>

<span class="org-keyword">instance</span> Functor <span class="org-type">Command</span> <span class="org-keyword">where</span>
    <span class="org-function-name">fmap</span> f <span class="org-rainbow-delimiters-depth-1">(</span>Command k c<span class="org-rainbow-delimiters-depth-1">)</span> = Command <span class="org-rainbow-delimiters-depth-1">(</span>f <span class="org-operator">.</span> k<span class="org-rainbow-delimiters-depth-1">)</span> c

<span class="org-function-name">toWireCmd</span> :: <span class="org-type">Cmd r</span> <span class="org-operator">-&gt;</span> <span class="org-type">ByteString</span>
<span class="org-function-name">toWireCmd</span> <span class="org-rainbow-delimiters-depth-1">(</span>Echo msg<span class="org-rainbow-delimiters-depth-1">)</span> = _
<span class="org-function-name">toWireCmd</span> <span class="org-rainbow-delimiters-depth-1">(</span>Hello ver<span class="org-rainbow-delimiters-depth-1">)</span> = _
<span class="org-function-name">toWireCmd</span> <span class="org-rainbow-delimiters-depth-1">(</span>Ping msg<span class="org-rainbow-delimiters-depth-1">)</span> = _

<span class="org-function-name">fromWireResp</span> :: <span class="org-type">Cmd r</span> <span class="org-operator">-&gt;</span> <span class="org-type">Resp</span> <span class="org-operator">-&gt;</span> <span class="org-type">Either RespError r</span>
<span class="org-function-name">fromWireResp</span> <span class="org-rainbow-delimiters-depth-1">(</span>Echo _<span class="org-rainbow-delimiters-depth-1">)</span> = fromResp
<span class="org-function-name">fromWireResp</span> <span class="org-rainbow-delimiters-depth-1">(</span>Hello _<span class="org-rainbow-delimiters-depth-1">)</span> = fromResp
<span class="org-function-name">fromWireResp</span> <span class="org-rainbow-delimiters-depth-1">(</span>Ping _<span class="org-rainbow-delimiters-depth-1">)</span> = fromResp
</pre>
</div>

<p>
(At this point I was still using <code>FromResp</code>.)
</p>

<p>
I also replaced the free applicative defined in the paper and started using
<a href="https://hackage.haskell.org/package/free">free</a>. A couple of type aliases make it a little easier to write nice signatures
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-keyword">type</span> Pipeline a = <span class="org-type">Ap Command a</span>

<span class="org-keyword">type</span> PipelineResult a = <span class="org-type">Validation </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">[</span></span><span class="org-type">RespError</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">]</span></span><span class="org-type"> a</span>
</pre>
</div>

<p>
and defining individual pipeline commands turned into something rather
mechanical. (I also swapped the order of the arguments to build a <code>Command</code> so I
can use point-free style here.)
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-function-name">liftPipe</span> :: <span class="org-rainbow-delimiters-depth-1">(</span>FromResp <span class="org-type">r</span><span class="org-rainbow-delimiters-depth-1">)</span> =&gt; <span class="org-type">Cmd r</span> <span class="org-operator">-&gt;</span> <span class="org-type">Pipeline r</span>
<span class="org-function-name">liftPipe</span> = liftAp <span class="org-operator">.</span> Command id

<span class="org-function-name">echo</span> :: <span class="org-type">Text</span> <span class="org-operator">-&gt;</span> <span class="org-type">Pipeline Text</span>
<span class="org-function-name">echo</span> = liftPipe <span class="org-operator">.</span> Echo

<span class="org-function-name">hello</span> :: <span class="org-type">Maybe Int</span> <span class="org-operator">-&gt;</span> <span class="org-type">Pipeline </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">()</span></span>
<span class="org-function-name">hello</span> = liftPipe <span class="org-operator">.</span> Hello

<span class="org-function-name">ping</span> :: <span class="org-type">Maybe Text</span> <span class="org-operator">-&gt;</span> <span class="org-type">Pipeline Text</span>
<span class="org-function-name">ping</span> = liftPipe <span class="org-operator">.</span> Ping
</pre>
</div>

<p>
One nice thing with switching to <i>free</i> was that serialisation became very simple
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-function-name">toWirePipeline</span> :: <span class="org-type">Pipeline a</span> <span class="org-operator">-&gt;</span> <span class="org-type">ByteString</span>
<span class="org-function-name">toWirePipeline</span> = runAp_ <span class="org-operator">$</span> \(Command _ c<span class="org-rainbow-delimiters-unmatched">)</span> <span class="org-operator">-&gt;</span> toWireCmd c
</pre>
</div>

<p>
On the other hand deserialisation became a little more involved, but it's not
too bad
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-function-name">fromWirePipelineResp</span> :: <span class="org-type">Pipeline a</span> <span class="org-operator">-&gt;</span> <span class="org-type"><span class="org-rainbow-delimiters-depth-1">[</span></span><span class="org-type">Resp</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">]</span></span> <span class="org-operator">-&gt;</span> <span class="org-type">PipelineResult a</span>
<span class="org-function-name">fromWirePipelineResp</span> <span class="org-rainbow-delimiters-depth-1">(</span>Pure a<span class="org-rainbow-delimiters-depth-1">)</span> _ = pure a
<span class="org-function-name">fromWirePipelineResp</span> <span class="org-rainbow-delimiters-depth-1">(</span>Ap <span class="org-rainbow-delimiters-depth-2">(</span>Command k c<span class="org-rainbow-delimiters-depth-2">)</span> p<span class="org-rainbow-delimiters-depth-1">)</span> <span class="org-rainbow-delimiters-depth-1">(</span>r : rs<span class="org-rainbow-delimiters-depth-1">)</span> = fromWirePipelineResp p rs <span class="org-operator">&lt;*&gt;</span> <span class="org-rainbow-delimiters-depth-1">(</span>k <span class="org-operator">&lt;$&gt;</span> liftError singleton <span class="org-rainbow-delimiters-depth-2">(</span>fromWireResp c r<span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
<span class="org-function-name">fromWirePipelineResp</span> _ _ = Failure <span class="org-rainbow-delimiters-depth-1">[</span>RespError <span class="org-string">"fromWirePipelineResp"</span> <span class="org-string">"Unexpected wire result"</span><span class="org-rainbow-delimiters-depth-1">]</span>
</pre>
</div>

<p>
Everything was working nicely and I started adding support for more commands. I
used the small service from work to guide my choice of what commands to add.
First out was <a href="https://redis.io/docs/latest/commands/del/">del</a>, then <a href="https://redis.io/docs/latest/commands/get/">get</a> and <a href="https://redis.io/docs/latest/commands/set/">set</a>. After adding <a href="https://redis.io/docs/latest/commands/lpush/">lpush</a> I was pretty much ready
to try to replace <i>hedis</i> in the service from work.
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-keyword">data</span> Cmd r <span class="org-keyword">where</span>
    <span class="org-comment">-- echo, hello, ping</span>
    Del :: <span class="org-rainbow-delimiters-depth-1">(</span>ToKey <span class="org-type">k</span><span class="org-rainbow-delimiters-depth-1">)</span> =&gt; <span class="org-type">NonEmpty k</span> <span class="org-operator">-&gt;</span> <span class="org-type">Cmd Int</span>
    Get :: <span class="org-rainbow-delimiters-depth-1">(</span>ToKey <span class="org-type">k</span>, FromResp <span class="org-type">r</span><span class="org-rainbow-delimiters-depth-1">)</span> =&gt; <span class="org-type">k</span> <span class="org-operator">-&gt;</span> <span class="org-type">Cmd r</span>
    Set :: <span class="org-rainbow-delimiters-depth-1">(</span>ToKey <span class="org-type">k</span>, ToArg <span class="org-type">v</span><span class="org-rainbow-delimiters-depth-1">)</span> =&gt; <span class="org-type">k</span> <span class="org-operator">-&gt;</span> <span class="org-type">v</span> <span class="org-operator">-&gt;</span> <span class="org-type">Cmd Bool</span>
    Lpush :: <span class="org-rainbow-delimiters-depth-1">(</span>ToKey <span class="org-type">k</span>, ToArg <span class="org-type">v</span><span class="org-rainbow-delimiters-depth-1">)</span> =&gt; <span class="org-type">k</span> <span class="org-operator">-&gt;</span> <span class="org-type">NonEmpty v</span> <span class="org-operator">-&gt;</span> <span class="org-type">Cmd Int</span>
</pre>
</div>

<p>
However, when looking at the above definition started I thinking.
</p>

<ul class="org-ul">
<li>Was it really a good idea to litter <code>Cmd</code> with constraints like that?</li>
<li>Would it make sense to keep the <code>Cmd</code> type a bit closer to the actual Redis
commands?</li>
<li>Also, maybe <code>FromResp</code> wasn't such a good idea after all, what if I remove it?</li>
</ul>

<p>
That brought me to the third version of the type for Redis commands.
</p>
</div>
</div>
<div id="outline-container-orgb20caeb" class="outline-2">
<h2 id="orgb20caeb">Converging and simplifying</h2>
<div class="outline-text-2" id="text-orgb20caeb">
<p>
While adding new commands and writing instances of <code>FromResp</code> I slowly realised
that my initial thinking of RESP3 as somewhat similar to JSON didn't really pan
out. I had quickly dropped <code>ToResp</code> and now the instances of <code>FromResp</code> didn't
sit right with me. They obviously had to "follow the commands", so to speak, but
at the same time allow users to bring their own types. For instance, <code>LSPUSH</code>
returns the number of pushed messages, but at the same time <code>GET</code> should be able
to return an <code>Int</code> too. This led to <code>Int</code>'s <code>FromResp</code> looking like this
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-keyword">instance</span> FromResp <span class="org-type">Int</span> <span class="org-keyword">where</span>
    <span class="org-function-name">fromResp</span> <span class="org-rainbow-delimiters-depth-1">(</span>BulkString bs<span class="org-rainbow-delimiters-depth-1">)</span> =
        <span class="org-keyword">case</span> parseOnly <span class="org-rainbow-delimiters-depth-1">(</span><span class="org-warning">AC8.</span>signed <span class="org-warning">AC8.</span>decimal<span class="org-rainbow-delimiters-depth-1">)</span> bs <span class="org-keyword">of</span>
            Left s <span class="org-operator">-&gt;</span> Left <span class="org-operator">$</span> RespError <span class="org-string">"FromResp"</span> <span class="org-rainbow-delimiters-depth-1">(</span><span class="org-warning">TL.</span>pack s<span class="org-rainbow-delimiters-depth-1">)</span>
            Right n <span class="org-operator">-&gt;</span> Right n
    <span class="org-function-name">fromResp</span> <span class="org-rainbow-delimiters-depth-1">(</span>Number n<span class="org-rainbow-delimiters-depth-1">)</span> = Right <span class="org-operator">$</span> fromEnum n
    <span class="org-function-name">fromResp</span> _ = Left <span class="org-operator">$</span> RespError <span class="org-string">"FromResp"</span> <span class="org-string">"Unexpected value"</span>
</pre>
</div>

<p>
I could see this becoming worse, take the instance for <code>Bool</code>, I'd have to
consider that
</p>

<ul class="org-ul">
<li>for <code>MOVE</code> <code>Integer 1</code> means <code>True</code> and <code>Integer 0</code> means <code>False</code></li>
<li>for <code>SET</code> <code>SimpleString "OK"</code> means <code>True</code></li>
<li>users would justifiably expect a bunch of bytestrings to be <code>True</code>, e.g.
<code>BulkString "true"</code>, <code>BulkString "TRUE"</code>, <code>BulkString "1"</code>, etc</li>
</ul>

<p>
However, it's impossible to cover <i>all</i> ways users can encode a <code>Bool</code> in a
<code>ByteString</code> so no matter what I do users will end up having to wrap <i>their</i>
<code>Bool</code> with <code>newtype</code> and implement a fitting <code>FromResp</code>. On top of that, even
thought I haven't found any example of it yet, I fully expect there to be,
somewhere in the large set of Redis commands, at least two commands each wanting
an instance of a basic type that simply can't be combined into a single
instance, meaning that the client library would need to do some <code>newtype</code>
wrapping too.
</p>

<p>
No, I really didn't like it! So, could I get rid of <code>FromResp</code> and still offer
users an API where they can user their own types as the result of commands?
</p>

<p>
To be concrete I wanted this
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-keyword">data</span> Cmd r <span class="org-keyword">where</span>
    <span class="org-comment">-- other commands</span>
    Get :: <span class="org-rainbow-delimiters-depth-1">(</span>ToKey <span class="org-type">k</span><span class="org-rainbow-delimiters-depth-1">)</span> =&gt; <span class="org-type">k</span> <span class="org-operator">-&gt;</span> <span class="org-type">Cmd </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">(</span></span><span class="org-type">Maybe ByteString</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">)</span></span>
</pre>
</div>

<p>
and I wanted the user to be able to conveniently turn a <code>Cmd r</code> into a <code>Cmd s</code>.
In other words, I wanted a <code>Functor</code> instance. Making <code>Cmd</code> itself a functor
isn't necessary and I just happened to already have a functor type that wraps
<code>Cmd</code>, the <code>Command</code> type I used for pipelining. If I were to use that I'd need
to write wrapper functions for each command though, but if I did that then I
could also remove the <code>ToKey~/~ToArg</code> constraints from the constructors of <code>Cmd
r</code> and put them on the wrapper instead. I'd get
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-keyword">data</span> Cmd r <span class="org-keyword">where</span>
    <span class="org-comment">-- other commands</span>
    Get :: <span class="org-type">Key</span> <span class="org-operator">-&gt;</span> <span class="org-type">Cmd </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">(</span></span><span class="org-type">Maybe ByteString</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">)</span></span>

<span class="org-function-name">get</span> :: <span class="org-rainbow-delimiters-depth-1">(</span>ToKey <span class="org-type">k</span><span class="org-rainbow-delimiters-depth-1">)</span> =&gt; <span class="org-type">k</span> <span class="org-operator">-&gt;</span> <span class="org-type">Command </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">(</span></span><span class="org-type">Maybe ByteString</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">)</span></span>
<span class="org-function-name">get</span> = Command id <span class="org-operator">.</span> Get <span class="org-operator">.</span> toKey
</pre>
</div>

<p>
I'd also have to rewrite <code>fromWireResp</code> so it's more specific for each command.
Instead of
</p>

<div class="org-src-container">
<pre class="src src-hskell">fromWireResp :: Cmd r -&gt; Resp -&gt; Either RespError r
fromWireResp (Get _) = fromResp
...
</pre>
</div>

<p>
I had to match up exactly on the possible replies to <code>GET</code>
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-function-name">fromWireResp</span> :: <span class="org-type">Cmd r</span> <span class="org-operator">-&gt;</span> <span class="org-type">Resp</span> <span class="org-operator">-&gt;</span> <span class="org-type">Either RespError r</span>
<span class="org-function-name">fromWireResp</span> _ <span class="org-rainbow-delimiters-depth-1">(</span>SimpleError err desc<span class="org-rainbow-delimiters-depth-1">)</span> = Left <span class="org-operator">$</span> RespError <span class="org-rainbow-delimiters-depth-1">(</span><span class="org-warning">T.</span>decodeUtf8 err<span class="org-rainbow-delimiters-depth-1">)</span> <span class="org-rainbow-delimiters-depth-1">(</span><span class="org-warning">T.</span>decodeUtf8 desc<span class="org-rainbow-delimiters-depth-1">)</span>
<span class="org-function-name">fromWireResp</span> <span class="org-rainbow-delimiters-depth-1">(</span>Get _<span class="org-rainbow-delimiters-depth-1">)</span> <span class="org-rainbow-delimiters-depth-1">(</span>BulkString bs<span class="org-rainbow-delimiters-depth-1">)</span> = Right <span class="org-operator">$</span> Just bs
<span class="org-function-name">fromWireResp</span> <span class="org-rainbow-delimiters-depth-1">(</span>Get _<span class="org-rainbow-delimiters-depth-1">)</span> Null = Right Nothing
...
<span class="org-function-name">fromWireResp</span> _ _ = Left <span class="org-operator">$</span> RespError <span class="org-string">"fromWireResp"</span> <span class="org-string">"Unexpected value"</span>
</pre>
</div>

<p>
Even though it was more code I liked it better than before, and I think it's
slightly simpler code. I also hope it makes the use of the API is a bit simpler
and clear.
</p>

<p>
Here's an example from the code for the service I wrote for work. It reads a UTC
timestamp stored in <code>timeKey</code>, the timestamp is a JSON string so it needs to be
decoded.
</p>

<div class="org-src-container">
<pre class="src src-haskell"><span class="org-function-name">readUTCTime</span> :: <span class="org-type">Connection</span> <span class="org-operator">-&gt;</span> <span class="org-type">IO </span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">(</span></span><span class="org-type">Maybe UTCTime</span><span class="org-type"><span class="org-rainbow-delimiters-depth-1">)</span></span>
<span class="org-function-name">readUTCTime</span> conn =
    sendCmd conn <span class="org-rainbow-delimiters-depth-1">(</span>maybe Nothing decode <span class="org-operator">&lt;$&gt;</span> get timeKey<span class="org-rainbow-delimiters-depth-1">)</span> <span class="org-operator">&gt;&gt;=</span> \<span class="org-keyword">case</span>
        Left _ <span class="org-operator">-&gt;</span> pure Nothing
        Right datum <span class="org-operator">-&gt;</span> pure datum
</pre>
</div>
</div>
</div>
<div id="outline-container-org0a0824d" class="outline-2">
<h2 id="org0a0824d">What's next?</h2>
<div class="outline-text-2" id="text-org0a0824d">
<p>
I'm pretty happy with the command type for now, though I have a feeling I'll
have to revisit <code>Arg</code> and <code>ToArg</code> at some point.
</p>

<p>
I've just turned the <code>Connection</code> type into a pool using <a href="https://hackage.haskell.org/package/resource-pool">resource-pool</a>, and I
started looking at pub/sub. The latter thing, pub/sub, will require some thought
and experimentation I think. Quite possibly it'll end up in a post here too.
</p>

<p>
I also have <i>a lot</i> of commands to add.
</p>
</div>
</div>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
Of course one could use RESP3 as the serialisation format for storing values
in Redis. Personally I think I'd prefer using something more widely used, and
easier to read, such as JSON or BSON.
</p></div></div>


</div>
</div><div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-haskell.html">haskell</a> <a href="https://magnus.therning.org/tag-redis.html">redis</a> </div>
]]></description>
  <category><![CDATA[haskell]]></category>
  <category><![CDATA[redis]]></category>
  <link>https://magnus.therning.org/2025-06-20-finding-a-type-for-redis-commands.html</link>
  <guid>https://magnus.therning.org/2025-06-20-finding-a-type-for-redis-commands.html</guid>
  <pubDate>Fri, 20 Jun 2025 23:40:00 +0200</pubDate>
</item>
<item>
  <title><![CDATA[Why I'm writing a Redis client package]]></title>
  <description><![CDATA[
<p>
A couple of weeks ago I needed a small, hopefully temporary, service at work. It
bridges a gap in functionality provided by a legacy system and the functionality
desired by a new system. The legacy system is cumbersome to work with, so we
tend to prefer building anti-corruption layers rather than changing it directly,
and sometimes we implement it as separate services.
</p>

<p>
This time it was good enough to run the service as a cronjob, but it did need to
keep track of when it ran the last time. It felt silly to spin up a separate DB
just to keep a timestamp, and using another service's DB is something I <i>really</i>
dislike and avoid.<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup> So, I ended up using the Redis instance that's used as a
cache by a OSS service we host.
</p>

<p>
The last time I had a look at the options for writing a Redis client in Haskell
I found two candidates, <a href="https://hackage.haskell.org/package/hedis">hedis</a> and <a href="https://hackage.haskell.org/package/redis-io">redis-io</a>. At the time I wrote a <a href="https://magnus.therning.org/2021-05-07-working-with-hedis.html">short note</a>
about them. This time around I found nothing much has changed, they are still
the only two contenders and they still suffer from the same issues
</p>

<ul class="org-ul">
<li><i>hedis</i> has still has the same API and I still find it as awkward.</li>
<li><i>redis-io</i> still requires a logger.</li>
</ul>

<p>
I once again decided to use <i>hedis</i> and wrote the service for work in a couple
of days, but this time I thought I'd see what it would take to remove the
requirement on <a href="https://hackage.haskell.org/package/tinylog">tinylog</a> from <i>redis-io</i>. I spent a few evenings on it, though I
spent most time on "modernising" the dev setup, using Nix to build, re-format
using <i>fourmolu</i>, etc. I did the same for <a href="https://hackage.haskell.org/package/redis-resp">redis-resp</a>, the main dependency of
<i>redis-io</i>. The result of that can be found on my gitlab account:
</p>

<ul class="org-ul">
<li><a href="https://gitlab.com/magus/redis-resp">https://gitlab.com/magus/redis-resp</a></li>
<li><a href="https://gitlab.com/magus/redis-io">https://gitlab.com/magus/redis-io</a></li>
</ul>

<p>
At the moment I won't take that particular experiment any further and given that
the most recent change to <i>redis-io</i> was in 2020 (according to its <a href="https://gitlab.com/twittner/redis-io/">git repo</a>)
I don't think there's much interest upstream either.
</p>

<p>
Making the changes to <i>redis-io</i> and <i>redis-resp</i> made me a little curious about
the <a href="https://redis.io/docs/latest/develop/reference/protocol-spec/">Redis protocol</a> so I started reading about it. It made me start thinking
about implementing a client lib myself. How hard could it be?
</p>

<p>
I'd also asked a question about Redis client libs on <a href="https://www.reddit.com/r/haskell/comments/1kk4a5v/redis_lib_for_haskell/">r/haskell</a> and a response
led me to <a href="https://hackage.haskell.org/package/redis-schema">redis-schema</a>. It has a very good README, and its section on
transactions with its observation that Redis transactions are a perfect match
for <code>Applicative</code>. This pushed me even closer to start writing a client lib.
What pushed me over the edge was the realisation that <a href="https://redis.io/docs/latest/develop/use/pipelining/">pipelining</a> also is a
perfect match for <code>Applicative</code>.
</p>

<p>
For the last few weeks I've spent some of my free time reading and experimenting
and I'm enjoying it very much. We'll see where it leads, but hopefully I'll at
least have bit more to write about it.
</p>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">

<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
One definition of a microservice I find very useful is "a service that owns
its own DB schema."
</p></div></div>


</div>
</div><div class="taglist"><a href="https://magnus.therning.org/tags.html">Tags</a>: <a href="https://magnus.therning.org/tag-haskell.html">haskell</a> <a href="https://magnus.therning.org/tag-redis.html">redis</a> </div>
]]></description>
  <category><![CDATA[haskell]]></category>
  <category><![CDATA[redis]]></category>
  <link>https://magnus.therning.org/2025-06-17-why-i'm-writing-a-redis-client-package.html</link>
  <guid>https://magnus.therning.org/2025-06-17-why-i'm-writing-a-redis-client-package.html</guid>
  <pubDate>Tue, 17 Jun 2025 22:43:00 +0200</pubDate>
</item>
</channel>
</rss>
