{
    "version": "https://jsonfeed.org/version/1",
    "title": "Mux Blog",
    "home_page_url": "https://mux-lang.dev/blog/",
    "description": "Mux Blog",
    "items": [
        {
            "id": "https://mux-lang.dev/blog/hindley-milner-type-system/",
            "content_html": "<p>I have been working on my programming language Mux for a while now, and I have been really interested in the way that different programming languages handle type systems. Mux uses a strong and static type system, and I have been exploring the different ways that type systems can be designed and implemented, and just adding in different features.</p>\n<p>While learning about this, the one type system that keeps coming up again and again is the Hindley-Milner type system.</p>\n<!-- -->\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-is-the-hindley-milner-hm-type-system\">What is the Hindley-Milner (HM) Type System<a href=\"https://mux-lang.dev/blog/hindley-milner-type-system/#what-is-the-hindley-milner-hm-type-system\" class=\"hash-link\" aria-label=\"Direct link to What is the Hindley-Milner (HM) Type System\" title=\"Direct link to What is the Hindley-Milner (HM) Type System\" translate=\"no\">​</a></h2>\n<p>One of the most influential type systems in the history of programming languages is the Hindley-Milner type system, which has been used in languages like ML, Haskell, and OCaml. HM has also had large influence on languages like Rust, C#, and Swift, which have adopted some of its features and concepts. However, despite its widespread adoption and influence, it still has several limitations and shortcomings that have been identified over the years.</p>\n<p>Mux specifically does not use the strictest version of the Hindley-Milner type system, and instead uses some different approaches to type inference and type checking. In this article, I will discuss some of the limitations of the Hindley-Milner type system, and why I chose to use a different approach in Mux.</p>\n<p>Due to the widespread usage of TypeScript as of late, I will be drawing similarities and differences between Mux and TS and their HM systems over the course of this article, but this applies to many PLs!</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"the-basic-idea\">The Basic Idea<a href=\"https://mux-lang.dev/blog/hindley-milner-type-system/#the-basic-idea\" class=\"hash-link\" aria-label=\"Direct link to The Basic Idea\" title=\"Direct link to The Basic Idea\" translate=\"no\">​</a></h2>\n<p>One of the simplest examples of HM type inference is the identity function:</p>\n<div class=\"terminal-code language-hm\" data-filename=\"HM\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>let identity = fun x -&gt; x</code></pre></div>\n<p>The compiler can infer that its type is:</p>\n<div class=\"terminal-code language-hm\" data-filename=\"HM\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>'a -&gt; 'a</code></pre></div>\n<p>Here, <code>'a</code> is a type variable. The identity function does not care what type it receives. Whatever type it receives, it returns that same type. This is called parametric polymorphism. The function can be used with an int, a string, or any other type without needing a separate implementation for each one. This smells a lot like generics!</p>\n<p>And that is exactly how TypeScript expresses this:</p>\n<div class=\"terminal-code language-typescript\" data-filename=\"TypeScript\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>function identity&lt;T&gt;(x: T): T {\n    return x;\n}</code></pre></div>\n<p>Mux makes a similar distinction to TypeScript:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>func identity&lt;T&gt;(T x) returns T {\n    return x\n}</code></pre></div>\n<p>So in this case, Mux is very similar to HM. The difference is in how Mux handles type inference and genericity in other cases. There are other concepts that we will go over first, but this is a good introduction to the basic idea of HM. Maybe you can see where this is going...</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-hindley-milner-got-right\">What Hindley-Milner Got Right<a href=\"https://mux-lang.dev/blog/hindley-milner-type-system/#what-hindley-milner-got-right\" class=\"hash-link\" aria-label=\"Direct link to What Hindley-Milner Got Right\" title=\"Direct link to What Hindley-Milner Got Right\" translate=\"no\">​</a></h2>\n<p>First, I think there are a lot of things that HM does that is very useful and important.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"type-inference\">Type Inference<a href=\"https://mux-lang.dev/blog/hindley-milner-type-system/#type-inference\" class=\"hash-link\" aria-label=\"Direct link to Type Inference\" title=\"Direct link to Type Inference\" translate=\"no\">​</a></h3>\n<p>HM's type inference is one of its biggest strengths. For example, instead of writing something to the effect of:</p>\n<div class=\"terminal-code language-hm\" data-filename=\"HM\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>let x: int = 42</code></pre></div>\n<p>we can write:</p>\n<div class=\"terminal-code language-hm\" data-filename=\"HM\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>let x = 42</code></pre></div>\n<p>and the compiler can determine that x has type int. TypeScript's is essentially the same:</p>\n<div class=\"terminal-code language-typescript\" data-filename=\"TypeScript\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>let x = 42;</code></pre></div>\n<p>The compiler knows that x is a number without requiring an annotation. Mux also supports this kind of local inference:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>auto x = 42</code></pre></div>\n<p>The difference is in where Mux wants inference to happen.</p>\n<p>Mux is intentionally more explicit about the types that define an API, while allowing inference inside expressions and local variables. More on what can and can't be inferred to come shortly.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"unification\">Unification<a href=\"https://mux-lang.dev/blog/hindley-milner-type-system/#unification\" class=\"hash-link\" aria-label=\"Direct link to Unification\" title=\"Direct link to Unification\" translate=\"no\">​</a></h3>\n<p>Another important part of HM is unification. Suppose the compiler knows that some value has type <code>'a</code> and later discovers that the value is being used as an int. The compiler can unify the two types, effectively determining that:</p>\n<div class=\"terminal-code language-hm\" data-filename=\"HM\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>'a = int</code></pre></div>\n<p>This is what allows HM to infer surprisingly complicated types without requiring annotations everywhere. TypeScript has a similar concept when it infers generic type parameters:</p>\n<div class=\"terminal-code language-typescript\" data-filename=\"TypeScript\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>function first&lt;T&gt;(items: T[]): T {\n    return items[0];\n}\n\nconst x = first([1, 2, 3]);</code></pre></div>\n<p>The compiler sees that the argument is a list of numbers, so it infers that T is a number and therefore x is a number. TypeScript can also do some more advanced inference (which i think is kinda cool btw). For example:</p>\n<div class=\"terminal-code language-typescript\" data-filename=\"TypeScript\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>function echo&lt;const T&gt;(value: T): T {\n    return value;\n}\n\nconst x = echo([1, 2, 3] as const);</code></pre></div>\n<p>The type checker can infer that T is the tuple type:</p>\n<div class=\"terminal-code language-typescript\" data-filename=\"TypeScript\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>readonly [1, 2, 3]</code></pre></div>\n<p>instead of <code>number[]</code>. This is a more advanced feature that is very cool, but Mux does not currently support it :(</p>\n<p>Mux does this inference for generic calls as well:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>func first&lt;T&gt;(list&lt;T&gt; items) returns T {\n    return items[0]\n}\n\nauto x = first([1, 2, 3])\n\n/* we can also define x as:\n * list&lt;int&gt; x = first([1, 2, 3])\n *\n * but we don't need to in this case :)\n */</code></pre></div>\n<p>The compiler can infer T is an int without requiring the explicit instantiation:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>first([1, 2, 3])</code></pre></div>\n<p>This is one of the places where Mux directly benefits from HM-style unification.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"what-hindley-milner-got-wrong-and-how-mux-does-it-better\">What Hindley-Milner Got Wrong, and How Mux Does It Better<a href=\"https://mux-lang.dev/blog/hindley-milner-type-system/#what-hindley-milner-got-wrong-and-how-mux-does-it-better\" class=\"hash-link\" aria-label=\"Direct link to What Hindley-Milner Got Wrong, and How Mux Does It Better\" title=\"Direct link to What Hindley-Milner Got Wrong, and How Mux Does It Better\" translate=\"no\">​</a></h2>\n<p>The interesting part is not that HM can infer types. It is how much information we want the compiler to infer in Mux. For Mux, I decided that inference should remove boilerplate without removing useful information from the code. This has its tradeoffs, but I like it so...</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"0-hm-generalizes-types-mux-declares-them\">0. HM Generalizes Types; Mux Declares Them<a href=\"https://mux-lang.dev/blog/hindley-milner-type-system/#0-hm-generalizes-types-mux-declares-them\" class=\"hash-link\" aria-label=\"Direct link to 0. HM Generalizes Types; Mux Declares Them\" title=\"Direct link to 0. HM Generalizes Types; Mux Declares Them\" translate=\"no\">​</a></h3>\n<p>Consider our identity function again. During type inference, the compiler can determine that its type is:</p>\n<div class=\"terminal-code language-hm\" data-filename=\"HM\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>'a -&gt; 'a</code></pre></div>\n<p>But it still needs to decide whether <code>'a</code> should mean one specific type, or whether the function can actually be used polymorphically. HM generalizes the type variable, giving us:</p>\n<div class=\"terminal-code language-hm\" data-filename=\"HM\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>forall 'a. 'a -&gt; 'a</code></pre></div>\n<p>That means each use of identity can pick its own <code>'a</code>:</p>\n<div class=\"terminal-code language-hm\" data-filename=\"HM\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>identity 42\nidentity \"hello\"</code></pre></div>\n<p>The first use can instantiate <code>'a</code> as int, while the second can instantiate it as string. This is an important distinction. The compiler is not simply saying that identity has some unknown type. It has determined that identity is universally polymorphic over <code>'a</code>. Inferring a type, then generalizing its free type variables, is a major part of what makes Hindley-Milner so powerful.</p>\n<p>Mux takes a different approach. Rather than discovering that a function should be universally polymorphic and then generalizing its inferred type, Mux makes the generic parameter explicit in the declaration. Consider:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>func identity&lt;T&gt;(T x) returns T</code></pre></div>\n<p>The <code>&lt;T&gt;</code> is there on purpose: the polymorphism is part of the function's declaration rather than something the compiler has to discover from the function body. This is one of the recurring design decisions in Mux: the compiler still performs type inference, but the programmer explicitly defines where polymorphism exists. Then at compilation time, Mux compiler will monomorphize the function. This is what Rust does, for example. So when we call identity with 42 and \"hello\" in Mux, we get something like this to use at runtime:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>func identity$string(string x) returns string;\nfunc identity$int(int x) returns int;</code></pre></div>\n<p>This bloats some of the code, but it is a way easier way to reason about, and debug a compiler. Plus, it is faster at runtime!</p>\n<p>TypeScript is already on Mux's side here. Generic parameters are explicit in the declaration:</p>\n<div class=\"terminal-code language-typescript\" data-filename=\"TypeScript\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>function map&lt;T, U&gt;(items: T[], f: (value: T) =&gt; U): U[] {\n    return items.map(f);\n}</code></pre></div>\n<p>The generic relationship is explicitly visible as T -&gt; U. A reader can immediately see that map takes an array of T, applies a function from T to U, and produces an array of U. An HM language can instead be written without explicitly declaring those type parameters:</p>\n<div class=\"terminal-code language-hm\" data-filename=\"HM\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>let map = fun f xs -&gt;\n    ...</code></pre></div>\n<p>The compiler can infer the equivalent polymorphic type. That is incredibly powerful, but I don't think it is the best tradeoff for Mux. Mux instead makes the public API explicit:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>func map&lt;T, U&gt;(\n    list&lt;T&gt; items,\n    func(T) returns U f\n) returns list&lt;U&gt; {\n    ...\n}</code></pre></div>\n<p>The Mux version is more verbose, but in my opinion it is more readable and easier to reason about because the important type relationships are visible where the function is defined. And when calling it, the compiler still does the boring work:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>auto strings = map(numbers, to_string)</code></pre></div>\n<p>rather than requiring:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>auto strings = map&lt;int, string&gt;(numbers, to_string)</code></pre></div>\n<p>This gives Mux a useful separation:</p>\n<blockquote>\n<p>The programmer declares the API. The compiler determines the concrete types.</p>\n</blockquote>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"1-dont-carry-unknown-types-forward\">1. Don't Carry Unknown Types Forward<a href=\"https://mux-lang.dev/blog/hindley-milner-type-system/#1-dont-carry-unknown-types-forward\" class=\"hash-link\" aria-label=\"Direct link to 1. Don't Carry Unknown Types Forward\" title=\"Direct link to 1. Don't Carry Unknown Types Forward\" translate=\"no\">​</a></h3>\n<p>The interesting thing about HM is that if the compiler doesn't know a type yet, it can introduce a type variable and keep going.</p>\n<p>For example, an empty list can conceptually have the type <code>'a list</code>. There is nothing inherently wrong with that. The compiler knows it is a list, but it does not yet know what the elements are.</p>\n<p>TypeScript has a similar situation:</p>\n<div class=\"terminal-code language-typescript\" data-filename=\"TypeScript\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>const empty = [];</code></pre></div>\n<p>The compiler has very little information about what empty is supposed to contain.</p>\n<p>Mux intentionally does not allow this ambiguity. Code with this declaration:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>auto empty = []</code></pre></div>\n<p>will result in the following message:</p>\n<div class=\"terminal-code language-text\" data-filename=\"Output\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>error: Cannot infer type for empty list literal\n--&gt; test.mux:1:14\n   |\n 1 | auto empty = []\n   |              ^\n   |\n= help: Use an explicit type annotation, e.g. list&lt;int&gt; myVar = []</code></pre></div>\n<p>This is a useful error because it tells the programmer exactly what information is missing and how to provide it. The other thing they can do is provide enough information for the compiler to infer it from the values in the list:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>auto filled = [1, 2, 3]</code></pre></div>\n<p>Here, the compiler can infer that filled is a list of ints. This raises a broader point. There is a difference between a type being representable by the type system and a type being useful to the programmer. HM is perfectly capable of representing <code>'a list</code>. But an <code>'a list</code> that no later use ever pins down is a type the compiler will eventually refuse anyway, at some random spot that has nothing to do with where the empty list was declared.</p>\n<p>The Mux programmer can also write:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>list&lt;int&gt; empty = []</code></pre></div>\n<p>Now there is no unresolved type variable. The programmer has explicitly provided the information the compiler was missing. This comes down to a subtle difference in philosophy.</p>\n<p>HM asks:</p>\n<blockquote>\n<p>Can this type remain polymorphic or unresolved?</p>\n</blockquote>\n<p>Mux asks:</p>\n<blockquote>\n<p>Do we have enough information to determine this type here?</p>\n</blockquote>\n<p>If the answer is no, Mux asks the programmer for more information instead of carrying the unknown type forward. That is a deliberate tradeoff, not a technical limitation. And I think the resulting code is easier to reason about. When I see:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>list&lt;int&gt; empty = []</code></pre></div>\n<p>I immediately know what the collection contains. I do not need to find another use of empty somewhere else in the program to figure out what type the compiler eventually inferred for it.</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"2-parametric-polymorphism-does-not-express-constraints\">2. Parametric Polymorphism Does Not Express Constraints<a href=\"https://mux-lang.dev/blog/hindley-milner-type-system/#2-parametric-polymorphism-does-not-express-constraints\" class=\"hash-link\" aria-label=\"Direct link to 2. Parametric Polymorphism Does Not Express Constraints\" title=\"Direct link to 2. Parametric Polymorphism Does Not Express Constraints\" translate=\"no\">​</a></h3>\n<p>Usage of <code>'a</code> tells us almost nothing about <code>'a</code>.</p>\n<p>That is exactly what we want for the identity function. It becomes less useful when writing functions that need to operate on the generic value. TypeScript solves this using constraints:</p>\n<div class=\"terminal-code language-typescript\" data-filename=\"TypeScript\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>function stringify&lt;T extends Printable&gt;(value: T): string {\n    return value.print();\n}</code></pre></div>\n<p>Now T is still generic, but the compiler knows that T satisfies Printable. Mux has the same basic idea through generic bounds and interfaces, more similar to Rust and Go in this regard:</p>\n<div class=\"terminal-code language-mux\" data-filename=\"Mux\"><div class=\"terminal-buttons\"><button class=\"terminal-copy-button\" aria-label=\"Copy code to clipboard\" title=\"Copy to clipboard\" type=\"button\"><svg aria-hidden=\"true\" focusable=\"false\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg></button><span role=\"status\" aria-live=\"polite\" style=\"position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0\"></span></div><pre class=\"shiki-pre\"><code>func stringify&lt;T is Printable&gt;(T value) returns string {\n    return value.print()\n}</code></pre></div>\n<p>This lets Mux express a distinction that plain HM polymorphism does not naturally express. The classic HM-era answer to this is type classes, like Haskell's, layered on top of the base system. Mux just uses a simpler spelling.</p>\n<p><code>T</code> means:</p>\n<blockquote>\n<p>This function is parameterized over some type T.</p>\n</blockquote>\n<p>While:</p>\n<p><code>T is Printable</code> means:</p>\n<blockquote>\n<p>This function is parameterized over some type T that is known to satisfy Printable.</p>\n</blockquote>\n<p>This is much more useful for a language with interfaces and generic programming. The compiler can still treat T as an unknown concrete type, while also knowing what operations are guaranteed to be available on it.</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_Vzrq\" id=\"where-this-leaves-mux\">Where This Leaves Mux<a href=\"https://mux-lang.dev/blog/hindley-milner-type-system/#where-this-leaves-mux\" class=\"hash-link\" aria-label=\"Direct link to Where This Leaves Mux\" title=\"Direct link to Where This Leaves Mux\" translate=\"no\">​</a></h2>\n<p>I think of Mux as borrowing one of HM's most useful pieces: unification-based type inference. Mux then builds a different type system around it:</p>\n<ul>\n<li class=\"\">explicit generics</li>\n<li class=\"\">local type inference</li>\n<li class=\"\">generic bounds</li>\n<li class=\"\">interfaces</li>\n<li class=\"\">nominal types</li>\n<li class=\"\">monomorphization</li>\n</ul>\n<p>The philosophy is fairly simple:</p>\n<blockquote>\n<p>The programmer should describe the important type relationships. The compiler should fill in the boring parts.</p>\n</blockquote>\n<p>HM showed how far a compiler can go in inferring those relationships automatically.</p>\n<p>Mux is therefore not trying to replace HM's inference model so much as make a different set of tradeoffs about where that inference is allowed to operate.</p>\n<p>What I learned from making Mux is that just because the compiler can infer something does not necessarily mean that it should.</p>",
            "url": "https://mux-lang.dev/blog/hindley-milner-type-system/",
            "title": "The MuxLang Type System: What Hindley-Milner Got Wrong",
            "summary": "I have been working on my programming language Mux for a while now, and I have been really interested in the way that different programming languages handle type systems. Mux uses a strong and static type system, and I have been exploring the different ways that type systems can be designed and implemented, and just adding in different features.",
            "date_modified": "2026-08-09T00:00:00.000Z",
            "author": {
                "name": "Derek Corniello",
                "url": "https://github.com/derekcorniello"
            },
            "tags": [
                "type-systems",
                "language-design",
                "hindley-milner"
            ]
        }
    ]
}