<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Unformed Delta - haskell</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/haskell.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sat, 09 May 2026 14:44:19 +0000</pubDate>
    <lastBuildDate>Sat, 09 May 2026 14:44:19 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
    <item>
      <title>7 Haskell effect systems</title>
      <description>&lt;p&gt;An overview of Haskell’s effect systems that I’ve used.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This was written pretty hastily for Inkhaven. I hope to return to this and add more details later.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;io&quot;&gt;IO&lt;/h2&gt;
&lt;p&gt;The simplest “effect system” in Haskell that has been around since the beginning. As an effect system, this just divides functions into pure and impure.&lt;/p&gt;

&lt;p&gt;This has a little bit of a special status because Haskell’s main function is declared &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main :: IO ()&lt;/code&gt;, meaning that all other effect systems must eventually delegate to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IO&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;mtl&quot;&gt;mtl&lt;/h2&gt;
&lt;p&gt;Monad transformers allow extending a monad with extra capabilities. This allows creating large stacks of monad transformers with a bunch of different effects, e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StateT AppState (ExceptT AppError (ReaderT Configuration IO a))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This quickly gets unwieldy because effects from lower layers need to be lifted through the upper layers.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mtl&lt;/code&gt; adds type classes for common kinds of effects, e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MonadState&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MonadError&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MonadReader&lt;/code&gt; which can be implemented generically to avoid needing to lift through monad transformers.&lt;/p&gt;

&lt;p&gt;As an added benefit this also makes it easier to test functions. A function requiring only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MonadState&lt;/code&gt; can just as easily be implemented using a pure function.&lt;/p&gt;

&lt;p&gt;The worst part about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mtl&lt;/code&gt; is that declaring new effects requires implementing every relevant type class when declaring a new effect. Conversely, implementing a new type class requires adding an implementation for every relevant monad transformer.&lt;/p&gt;

&lt;p&gt;This is called the \(n^2\) instances problem. It’s possible to work around this for the most part with &lt;a href=&quot;/byPuFMGvYUE0/haskell-the-overlappable-monadtrans-instance-pattern&quot;&gt;Haskell: the OVERLAPPABLE MonadTrans instance pattern&lt;/a&gt;, but it still requires more boilerplate than other effect systems we will see.&lt;/p&gt;

&lt;h2 id=&quot;readert-io--unliftio&quot;&gt;ReaderT IO / unliftio&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReaderT IO&lt;/code&gt; makes the observation that most custom effects can easily be represented by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IO&lt;/code&gt; anyways.&lt;/p&gt;

&lt;p&gt;Instead of implementing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MonadState&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StateT&lt;/code&gt; it can just as easily be implemented by manipulating an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IORef&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IO&lt;/code&gt;. Why use separate exceptions from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExceptT&lt;/code&gt; when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IO&lt;/code&gt; exceptions can achieve the same purpose?&lt;/p&gt;

&lt;p&gt;Because extra parameters are still annoying to pass around, it’s common to still use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReaderT&lt;/code&gt; type to remove boilerplate associated with passing them.&lt;/p&gt;

&lt;p&gt;Finally, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unliftio&lt;/code&gt; makes it easier to express higher order operations like bracket. Because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReaderT&lt;/code&gt; isn’t stateful it’s possible to “unlift” it, which makes it possible to represent more generic error handling operations.&lt;/p&gt;

&lt;p&gt;It remains a little bit hard to define custom effects and reinterpret them flexibly with this approach. To implement a pure version of an effect, you still often end up stuck with the complexity of monad transformer stacks and the \(n^2\) instances problem.&lt;/p&gt;

&lt;h2 id=&quot;polysemy&quot;&gt;polysemy&lt;/h2&gt;
&lt;p&gt;Algebraic effect systems attempt to get rid of the boilerplate involved in defining custom type classes for effects once and for all. They also try to implement fancier algebraic effect patterns.&lt;/p&gt;

&lt;p&gt;Based on the weaving pattern introduced by &lt;a href=&quot;https://www.cs.ox.ac.uk/people/nicolas.wu/papers/Scope.pdf&quot;&gt;Effect Handler’s in Scope&lt;/a&gt;, this library is based on free monads, keeping track of an open union of capabilities.&lt;/p&gt;

&lt;h2 id=&quot;fused-effects&quot;&gt;fused-effects&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fused-effects&lt;/code&gt; is pretty much like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;polysemy&lt;/code&gt; but uses type classes instead of an open union. This provides a bit more efficiency at runtime trading off for greater boilerplate.&lt;/p&gt;

&lt;h2 id=&quot;in-other-words&quot;&gt;in-other-words&lt;/h2&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;in-other-words&lt;/code&gt; is the most creative effect system I’ve seen so far. It provides a really ergonomic interface by providing granular primitive effects that encapsulate higher order effect patterns. User defined effects can be translated into these effects, which makes gets rid of some of the complexity imposed by polysemy and fused-effect’s weaving pattern.&lt;/p&gt;

&lt;p&gt;In practice its biggest flaw is its lack of documentation, and the raw complexity of the effects it offers. Some of its effects are extremely general, and reasoning through how they can be instantiated into something useful is really hard.&lt;/p&gt;

&lt;h2 id=&quot;effectful&quot;&gt;effectful&lt;/h2&gt;
&lt;p&gt;Effectful is the application of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ReaderT IO&lt;/code&gt; / unliftio’s lessons to algebraic effect systems. It implements everything in terms of IO, but wraps it up in a neat interface that makes it easier to work with.&lt;/p&gt;

&lt;p&gt;It’s also able to provide a reasonably safe pure interface.&lt;/p&gt;

&lt;p&gt;This is currently my favorite effect system for new projects.&lt;/p&gt;
</description>
      <pubDate>Mon, 27 Apr 2026 06:40:00 +0000</pubDate>
      <link>https://unformeddelta.wiki/7FzDAf8VJ7Fo/7-haskell-effect-systems</link>
      <guid isPermaLink="true">https://unformeddelta.wiki/7FzDAf8VJ7Fo/7-haskell-effect-systems</guid>
      
      <category>haskell</category>
      
      <category>inkhaven</category>
      
    </item>
    
    <item>
      <title>an expressive programming language</title>
      <description>&lt;p&gt;&lt;em&gt;Thanks to Alok Singh for the rough format and inspiration to write this post.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I tried naming as may programming languages as I could and came up with these before I got bored: C Rust Perl Bash Zsh Fish Zig C++ D Visual Basic Prolog Racket Elisp VimScript Lua Ruby Idris Agda Rocq C# F# F* Clojure Kotlin Scala Java ECMAScript TypeScript Raku Python OCaml Standard ML Jai Pony koka Cyclone Unison Swift Objective C Piet J APL Brainfuck Purescript Elm JIF (Java Information Flow) moss LLVM CUDA MLIR x86 ARM MIPS&lt;/p&gt;

&lt;p&gt;But Haskell is my favorite.&lt;/p&gt;

&lt;h2 id=&quot;why&quot;&gt;Why?&lt;/h2&gt;
&lt;p&gt;It’s expressive. Things that other languages must implement as builtin features, can and are implemented as libraries. This gives you the power to customize the language however you see fit.&lt;/p&gt;

&lt;p&gt;In most languages the and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;&amp;amp;&lt;/code&gt; operator needs special compiler treatment to ensure that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false &amp;amp;&amp;amp; doSomethingExpensive()&lt;/code&gt; doesn’t evaluate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doSomethingExpensive()&lt;/code&gt; unnecessarily. In Haskell laziness gives you this for free. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;amp;&amp;amp;&lt;/code&gt; operator can be defined in the standard library just like any other function without any special compiler treatment:&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;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;True&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;False&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you evaluate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False &amp;amp;&amp;amp; someExpensiveComputation&lt;/code&gt;, laziness means that the second clause never evaluates &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;someExpensiveComputation&lt;/code&gt;, the computation only needs to see that the first argument is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;False&lt;/code&gt; to produce its result.&lt;/p&gt;

&lt;p&gt;But there’s a problem with laziness. It makes it hard to predict what order things will get evaluated in, because you need to look at the implementation of your function to know what order its arguments will be evaluated in. For IO like reading a file or printing to the console you need a way to guarantee the order things run in. Haskell adopted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do&lt;/code&gt; notation and monads for this purpose. But it turns out that it’s a very general abstraction that generalizes exception handling, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt;, generators (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt;), and many other things.&lt;/p&gt;

&lt;p&gt;But so far we’ve only listed two language features: laziness and monads. By “avoiding success at all costs” Haskell has accumulated decades of experimental language features produced by programming languages research. This allows Haskell to absorb features and express patterns invented in pretty much any other programming language.&lt;/p&gt;

&lt;p&gt;RSpec is a Ruby library for writing unit tests. It lets you describe the behaviors of your program using near natural language syntax.&lt;/p&gt;
&lt;div class=&quot;language-ruby 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;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Order&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;sums the prices of its line items&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LineItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:price&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Money&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:USD&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;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LineItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:price&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Money&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:USD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:quantity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Money&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;5.55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:USD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Without even needing to resort to &lt;a href=&quot;https://wiki.haskell.org/Template_Haskell&quot;&gt;macros&lt;/a&gt; HSpec embeds a very similar syntax:&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;n&quot;&gt;spec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Spec&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;spec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;sums the prices of its line items&quot;&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;kr&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderFromEntries&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;LineItem&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Money&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;USD&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;n&quot;&gt;quantity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;LineItem&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;price&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Money&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;USD&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;n&quot;&gt;quantity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;orderTotal&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shouldBe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Money&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;5.55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;currency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;USD&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;There’s even database libraries like squeal that embed SQL syntax in a type safe way without needing macros:&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;n&quot;&gt;getUsers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Statement&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;DB&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;getUsers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;select_&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:*&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userEmail&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;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;innerJoin&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emails&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&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;Personally that’s too many operators and too complicated types even for me, but I like the idea that it’s possible in the programming language I use. Maybe someday I’ll have a problem for which that complexity is worth it. The thing that I love the most about Haskell is that people do these things even if its not worth it.&lt;/p&gt;

&lt;p&gt;Through clever encodings, it’s even possible to do anything you can do in a dependently typed programming language/proof assistant like Lean and Rocq with &lt;a href=&quot;https://hackage.haskell.org/package/singletons&quot;&gt;a little bit extra boilerplate&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-languages-with-features-i-envy&quot;&gt;The languages with features I envy&lt;/h2&gt;
&lt;p&gt;When writing Haskell, there’s still some languages left with features that I envy:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Any programming language with fast compile times: I used to work at a company with a ~2 million lines of code Haskell codebase. It took 3-4 hours to compile from scratch.&lt;/li&gt;
  &lt;li&gt;True dependently typed programming languages (like Lean, Idris, Agda, Rocq) are way more ergonomic for any kind of advanced type level programming. Haskell’s &lt;a href=&quot;https://ghc.serokell.io/dh&quot;&gt;working on becoming Dependent Haskell&lt;/a&gt;, but it’s still a really long way off.&lt;/li&gt;
  &lt;li&gt;Languages with better macro systems, mostly Racket, who’s macro system is powerful enough to implement &lt;a href=&quot;https://lexi-lambda.github.io/hackett/&quot;&gt;Hackett&lt;/a&gt;, a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#lang&lt;/code&gt; pragma that more or less implements Haskell in Racket.&lt;/li&gt;
  &lt;li&gt;Rust: while Haskell has linear types, they are not nearly as mature as Rust’s uniqueness types for resource management.&lt;/li&gt;
  &lt;li&gt;Prolog: logic programming can be more declarative than laziness.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My dream is a programming language that can subsume all of these features.&lt;/p&gt;

&lt;h2 id=&quot;epilogue&quot;&gt;Epilogue&lt;/h2&gt;
&lt;p&gt;I’m not sure there is a perfect programming language, nor will there probably ever be. Perhaps someday there’ll be a programming language that combines all the features I like. &lt;a href=&quot;https://alok.github.io/lean-pages/perfectable-lean/&quot;&gt;Perhaps Lean will be perfected&lt;/a&gt;. But who knows, for now Haskell is still my favorite programming language.&lt;/p&gt;
</description>
      <pubDate>Wed, 08 Apr 2026 05:43:00 +0000</pubDate>
      <link>https://unformeddelta.wiki/GEbCU1EGqkQU/an-expressive-programming-language</link>
      <guid isPermaLink="true">https://unformeddelta.wiki/GEbCU1EGqkQU/an-expressive-programming-language</guid>
      
      <category>inkhaven</category>
      
      <category>haskell</category>
      
      <category>recommended</category>
      
      <category>programming-languages</category>
      
    </item>
    
    <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>
    
    <item>
      <title>Haskell: Strict vs Lazy ByteString</title>
      <description>&lt;p&gt;The Haskell ecosystem’s preferred way of representing binary data is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt; type. The &lt;a href=&quot;https://hackage-content.haskell.org/package/bytestring-0.12.2.0&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bytestring&lt;/code&gt;&lt;/a&gt; introduces its two variants like so:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;ul&gt;
    &lt;li&gt;Strict &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s keep the string as a single large array. This makes them convenient for passing data between C and Haskell.&lt;/li&gt;
    &lt;li&gt;Lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s use a lazy list of strict chunks which makes it suitable for I/O streaming tasks.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Otherwise, the documentation expresses little preference between strict and lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;The broader library ecosystem often offers functions for working with both lazy and strict &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s. For example, in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aeson&lt;/code&gt; exposes &lt;a href=&quot;https://hackage.haskell.org/package/aeson-2.2.3.0/docs/Data-Aeson.html#v:decode&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decode&lt;/code&gt;&lt;/a&gt; which decodes a json value from a lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt; in addition to a strict variant &lt;a href=&quot;https://hackage.haskell.org/package/aeson-2.2.3.0/docs/Data-Aeson.html#v:decodeStrict&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;decodeStrict&lt;/code&gt;&lt;/a&gt;. From this, it’s reasonable to assume that lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt; is the default, because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aeson&lt;/code&gt; exposes it unqualified, while relegating strict to a section with “Variants for strict bytestrings”.&lt;/p&gt;

&lt;p&gt;However, as a general rule, I recommend sticking to strict &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s as a default:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;more memory efficient: lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s include extra bookkeeping overhead for maintaining its list of strict &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt; chunks.&lt;/li&gt;
  &lt;li&gt;reads are faster: in a strict &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;, reading any position in the string is just reading from an offset in memory. For a lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt; its necessary to follow pointers for values later in the bytestring.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(1)&lt;/code&gt; conversion to lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s: converting a lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt; to a strict one is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(n)&lt;/code&gt;, requiring copying the lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;’s chunks into a single contiguous block of memory. Strict &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s don’t need to be split into smaller chunks, the existing memory reused.&lt;/li&gt;
  &lt;li&gt;avoid lazy IO: while often convenient seeming, lazy IO leads to hard to diagnose bugs, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOException&lt;/code&gt;s being thrown from pure code. You’re generally better off using a streaming framework like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conduit&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pipes&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;streamly&lt;/code&gt; together with strict &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Output oriented APIs, like serialization, are the one scenario where lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s make a good amount of sense:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;builders produce lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data.ByteString.Builder&lt;/code&gt; only exposes &lt;a href=&quot;https://hackage-content.haskell.org/package/bytestring-0.12.2.0/docs/Data-ByteString-Builder.html#v:toLazyByteString&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toLazyByteString&lt;/code&gt;&lt;/a&gt; for converting a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Builder&lt;/code&gt; into an actual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;. It takes &lt;a href=&quot;https://hackage-content.haskell.org/package/bytestring-0.12.2.0/docs/Data-ByteString.html#v:toStrict&quot;&gt;an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(n)&lt;/code&gt; conversion&lt;/a&gt; to turn the result into a strict &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;concatenation of lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s is more efficient: lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;’s list of chunks allows appending new chunks without copying entire buffers of data. Use a builder instead of concatenating lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s directly to avoid creating lots of small inefficient chunks if possible though!&lt;/li&gt;
  &lt;li&gt;APIs for encoding/serializing often produce lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;s: because of the above its common for serialization operations like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aeson&lt;/code&gt;’s &lt;a href=&quot;https://hackage.haskell.org/package/aeson-2.2.3.0/docs/Data-Aeson.html#v:encode&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;encode&lt;/code&gt;&lt;/a&gt; to only expose versions producing a lazy &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ByteString&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
</description>
      <pubDate>Mon, 01 Sep 2025 04:35:00 +0000</pubDate>
      <link>https://unformeddelta.wiki/qeIskL2GME7w/haskell-strict-vs-lazy-bytestring</link>
      <guid isPermaLink="true">https://unformeddelta.wiki/qeIskL2GME7w/haskell-strict-vs-lazy-bytestring</guid>
      
      <category>recommended</category>
      
      <category>haskell</category>
      
    </item>
    
  </channel>
</rss>
