<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Unformed Delta - programming-pattern</title>
    <description>A place to collect the things I learn, figure out, or find interesting.
</description>
    <link>https://unformeddelta.wiki/</link>
    <atom:link href="https://unformeddelta.wiki/feed/programming-pattern.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Mon, 06 Apr 2026 08:15:48 +0000</pubDate>
    <lastBuildDate>Mon, 06 Apr 2026 08:15:48 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
    <item>
      <title>Haskell: the re-export module X pattern</title>
      <description>&lt;p&gt;Haskell’s syntax for declaring module exports is clunky and second-class. Exports must be declared after the module header either by name, or re-exporting an entire module:&lt;/p&gt;
&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Foo&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Baz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Baz&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This re-exports all of the identifiers exported by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Baz&lt;/code&gt;. If instead you only wanted to re-export some of the identifiers, naively you would need to list them all out individually:&lt;/p&gt;
&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Foo&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;baz1&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Bar&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Baz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Just reading the export list, it can be unclear which module the identifiers are being imported from: e.g. is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bar&lt;/code&gt; actually exported by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bar&lt;/code&gt; or is it actually provided by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Baz&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;re-export module X pattern&lt;/strong&gt; is a simple trick to solve this problem. Instead of re-exporting identifiers individually, use a qualified import to say up front which identifiers you plan to re-export:&lt;/p&gt;
&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Foo&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Bar&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Baz&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;baz1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This makes it easy to see which modules and which identifiers we are re-exporting identifiers from, no matter how many. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X&lt;/code&gt; is conventionally used as the module name, i.e. e&lt;strong&gt;X&lt;/strong&gt;port.&lt;/p&gt;

&lt;p&gt;There’s two primary scenarios where I reach for this pattern:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;building a custom prelude&lt;/strong&gt;: Custom preludes need to re-export lots of identifiers from lots of different modules. To provide some internal organization and make your prelude more discoverable it’s often useful to break them into submodules, e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyPrelude.Effects&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MyPrelude.MaybeEither&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;building a utility module extending another module&lt;/strong&gt;: Maybe you have a custom combinator for operating on maps not provided by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data.Map.Strict&lt;/code&gt;. I like putting this kind of combinator in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Utils.Map&lt;/code&gt; module, and then also re-exporting everything I want to use from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data.Map.Strict&lt;/code&gt;. Then you can just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import qualified Utils.Map as Map&lt;/code&gt; instead of needing to also &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import qualified Data.Map.Strict as Map&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The following example demonstrates a couple of important gotchas:&lt;/p&gt;
&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Foo&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Bar&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Baz&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;baz1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Perhaps unexpectedly, this example exports &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bar.bar&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Foo.bar&lt;/code&gt;. Also, if you try using (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bar + 1&lt;/code&gt;) or re-exporting (e.g. adding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bar&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;module Foo&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Foo&lt;/code&gt;’s export list) &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bar&lt;/code&gt; you’ll get &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ambiguous occurrence ‘bar’&lt;/code&gt;. You can disambiguate by exporting the fully qualified module name, i.e. adding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Foo.bar&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bar.bar&lt;/code&gt; to the export list (instead of doing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import Bar as X (bar)&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Additionally, though &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Foo&lt;/code&gt; looks like it might, it doesn’t actually re-export &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;baz1&lt;/code&gt;. In order for an identifier to be re-exportable, it must be imported unqualified.&lt;/p&gt;

&lt;p&gt;Here’s an example that demonstrates a couple of useful tricks:&lt;/p&gt;
&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Foo&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Bar&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Bar&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Baz&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hiding&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bar2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that you can have multiple imports of the same module, here &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bar&lt;/code&gt;. This can be useful when you’re providing some functions that work with the types in an existing module, but don’t want to re-export the whole original module.&lt;/p&gt;

&lt;p&gt;Finally, note that using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hiding&lt;/code&gt; lets you re-export a whole module less some identifiers, here &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Baz&lt;/code&gt;. This can be useful when you want to re-export everything but one of your identifiers conflicts.&lt;/p&gt;
</description>
      <pubDate>Sat, 04 Apr 2026 22:46:00 +0000</pubDate>
      <link>https://unformeddelta.wiki/rJylKYFWAsAP/haskell-the-re-export-module-x-pattern</link>
      <guid isPermaLink="true">https://unformeddelta.wiki/rJylKYFWAsAP/haskell-the-re-export-module-x-pattern</guid>
      
      <category>haskell</category>
      
      <category>programming-pattern</category>
      
      <category>inkhaven</category>
      
    </item>
    
  </channel>
</rss>
